1 Objectives

The objectives of this notebook are to analyze the results from the first follow up round of the Rwanda long term soil health study.

2 Key Takeaways

See section with Notes for Nathaniel

See section with Notes for Patrick and Step

Paired Yield and Soil ids are a mess. We lose a lot of observations due to unreconciliable duplicates or ids that simply don’t have a match. We lose almost 500 observations.

See initial yield response analysis

TODO - check projection from baseline maps, are they shifted over? TODO - how to connect photos to farmers for enumerators

3 Data Prep

I’m going to load the baseline data from the baseline analysis. The report and data can be found here. I’ll load the new data directly from CommCare. The original baseline data object was d but I’m going to make it b. Each subsequent round will be r1, r2 and so on.

Overall I want to bring in 3 data sources:

  • Basline survey data and soil data
  • Round 1 survey and and soil data from 16B
  • Round 1 yield and soil data - these data come from paired climbing bean harvest measurements and soil samples from 16B
  • We can also look at maize paired yield and soil samples from 17A.

3.1 Baseline data

dataDir <- normalizePath(file.path("..", "..", "data"))
forceUpdateAll <- FALSE
baselineDir <- normalizePath(file.path("..", "rw_baseline", "data"))
load(file=paste0(baselineDir, "/shs rw baseline full soil.Rdata")) # obj d
b <- baseVars

Context point: The baseline data has 2439 rows. This is 9 fewer rows than we expected in the baseline. This is because of some farmers not being surveyed as expected. See the baseline report for more details. Also, these baesline values have te

Alex Villec wrote a cleaning script to deal with the first round of Rwanda SHS follow up data and make key adjustments to the data. To utilize that do file here, I’m going to download the data from Commcare, save it, and have the dofile access that file to execute. However, the original file Alex was using had different variable names than the file pulled by the API. The options from here are to just go with the file from Alex or to align the variable names between his version and the CC version. It’s valuable to have the data directly from CC but it’ll involve more work up front

3.2 Round 1 data

source("../oaflib/commcareExport.R")
r <- getFormData("oafrwanda", "M&E", "16B Ubutaka (Soil)", forceUpdate = F)
[1] "found fdd434a62c6512b320a4cb8c4fb872a"
write.csv(r, file="rawCcR1Data.csv", row.names = F)

The first round of data from CommCare has 2380 observations. This leaves XX number of farmers unsurveyed in the first survey round. See this cleaning file for more information on the farmers we did not find again in the first follow up.

Here I’m going to call the STATA cleaning file to make AV’s changes to the R1 follow up data. This requires that the data from CC have the same variable names as the STATA cleaning file. I’m going to try to execute that here:

stataDir <- normalizePath(file.path("..", "rw_round_1_check"))

Here I access the soil predictions from the OAF soil lab. Patrick Bell manages the lab and Mike Barber oversees the prediction scripts.

soilDir <- normalizePath(file.path("..", "..", "data", "OAF Soil Lab Folder", "Projects", "rw_shs_second_round", "4_predicted", "other_summaries"))
soil <- read.csv(file=paste(soilDir, "combined-predictions-including-bad-ones.csv", sep = "/"))
idDir <- normalizePath(file.path("..", "..", "data", "OAF Soil Lab Folder", "Projects", "rw_shs_second_round", "5_merged"))
Identifiers <- read_excel(paste(idDir,"database.xlsx",sep="/"), sheet=1)

Combine the available data by farmer and resolve merging issues. These data can be combined long as long as the variable names are consistent or wide. I’m going to combine the data long and use split type commands to aggregate the data more easily. Confirm the variable names are consistent. By advancing this code on 5/9/17, I’m for the time being ignoring the cleaning Alex did in his do file. I’ll need to go back and incorporate those changes.

TODO: see if the variables names in Alex’s raw data, shared by Nathaniel, match the data I’m downloading from commcare. If so, don’t use the var_names.xlsx sheet and instead use those variable names and Alex’s do file to preserve all of his changes.

Not many of the names are the same. I’ve downloaded the meta data from CommCare which I’ll use to simplify the cleaning of the round 1 data. I’m also going to reshape the baseline variable names to simplify the matching of baseline variables to round 1 variables.

datNames <- function(dat){
  varNames = names(dat)
  exVal = do.call(rbind, lapply(varNames, function(x){
    val = dat[1:3,x]
    return(val)
  }))
  
  out = cbind(varNames, exVal)
  return(out)
}
baseNames <- datNames(b)
write.csv(baseNames, file="baseline var names.csv", row.names = F)

Load Alex’s raw data and take the variable names from this. If I can align these variable names with the data from CC I can then execute Alex’s cleaning script on the CC data and proceed with combining the data

3.3 Stata .do file

rawDir <- normalizePath(file.path("Soil health study (year one)", "data"))
avRaw <- read.csv(paste(rawDir, "y1_shs_rwanda_28sep.csv", sep = "/"), stringsAsFactors = F)

It looks like the data from CommCare aligns with the raw data Alex worked with at info_formid which is the second index for avRaw and the 10th index for r. Let’s just try transferring them over and the work of updating the variable names through the CC codebook export may not be necessary!

varTest <- data.frame(fromcc = names(r)[10:409], fromav = names(avRaw)[2:401])
# head(varTest)
# tail(varTest)
#varTest[90:120,]
write.csv(varTest, file="variableNameCheck.csv")

It seems to line up okay (with some adjustments)! To incorporate Alex’s cleaning code I have to export the data from R to a form Stata accept, run the code, and then load the data back in.

This function will remove all strange outputs from the data from CommCare so that the STATA code works

# charClean <- function(df){
#   
#   df <- as.data.frame(lapply(df, function(x){
#   x = gsub("'", '', x)
#   x = gsub("^b", '', x)
#   x = ifelse(grepl("map object", x)==T, NA, x)
#   return(x)
#   }))
# return(df)
# }
# 
# r <- charClean(r)

Here is where I actually update the names in r to match Alex’s original data.

names(r)[10:409] <- names(avRaw)[2:401]
#export so stata can run - check for variable names longer than 32char
table(nchar(names(r)))

 2  6  7  8  9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 32 33 34 
 1  4  3  1  1  2  6  1  1  2  3  5 17 11 16 12  5  8  1  7  1  3  9  9  3  7  2  3  1 
36 37 38 39 40 41 42 43 44 45 46 47 48 49 51 52 
28 16 47 32 11  7 27 18 21 31 10  7  4  3  1  1 
write.csv(r, file="toBeCleanedStata.csv", row.names = F)
stata("cleans_y1_shs_rwanda.do", stata.echo=F)

Now load the result of the Stata file

r <- read.csv("cleanedforR.csv", stringsAsFactors = F)

4 Cleaning

The r dataframe has many more variables than the baseline survey. This was in part expected; we added questions to the first follow up round based on lessons from the baseline. It’s also due to how the survey was set up in CommCare. Before combining the baseline and the first follow up round I need to:

  • reshape the round 1 variables so that they appropriately match the baseline variables
  • Clean those variales or prepare them as need be for a
  • For variables with no match, clean

4.1 Drop variables

toDrop <- c("appformid", "id", "domain", "metadatadeviceid")
r <- r[,!names(r) %in% toDrop]
source("../oaflib/misc.R")
names(r) <- gsub("^y1_|intro_", "", names(r))
r[r=="."] <- NA
r <- divideGps(r, "gps_coord")

4.2 Categorical variables

The responses of the categorical variables should be regulated through CC, however, to check, make a table that shows the top ten responses in descending order and make a graph of response counts to know what to check. I’ll then capture any characters that should be numeric and convert them.

catVars <- names(r)[sapply(r, function(x){
  is.character(x)
})]
enumClean <- function(dat, x, toRemove){
  dat[,x] <- ifelse(dat[,x] %in% toRemove, NA, dat[,x])
  return(dat[,x])
}
strTable <- function(dat, x){
  varName = x
  tab = as.data.frame(table(dat[,x], useNA = 'ifany'))
  tab = tab[order(tab$Freq, decreasing = T),]
  end = ifelse(length(tab$Var1)<10, length(tab$Var1), 10)
  repOrder = paste(tab$Var1[1:end], collapse=", ")
  out = data.frame(variable = varName,
                   responses = repOrder)
  
  return(out)
}
# clean up known values
catEnumVals <- c("-99", "-88", "- 99", "-99.0", "88", "_88", "- 88", "0.88",
                 "--88", "__88", "-88.0", "99.0")
r[,catVars] <- sapply(catVars, function(y){
  r[,y] <- enumClean(r,y, catEnumVals)
})
responseTable <- do.call(rbind, lapply(catVars, function(x){
  strTable(r, x)
}))

4.2.1 Categorical response table

A simple table to preview the values in the data. The values are ranked by frequency.

kable(responseTable)
variable responses
metadatauserid c3e5e4d69726a6587d9d5739f3961b03, ab7675956342e27f3a134b45731ca6f9, a8f48eb2ccc435935cdefec31a49f512, 2da910f9aa814b352b62821db7ac30fc, 7e1b7bc7a7147b9f4ddfedab54e8e470, 43ab9369b7e43edaa7d9614594f4d1dd, 9938a37f596038d85181e4d38cff2433, bfb7f31368600aefe2c4386ad49c5126, 4a69416450e53b6e762ea707aaf80104, 089ae26df7d5ea3886dbbe3709c34013
metadatausername umushakashatsi, umushakashatsi3, umushakashatsi72, umushakashatsi42, umushakashatsi58, umushakashatsi14, umushakashatsi66, umushakashatsi7, umushakashatsi13, umushakashatsi73
metadatatimestart 2016-08-04 11:37:19, 2016-08-05 09:11:39, 2016-08-08 10:16:44, 2016-08-17 09:17:49, 2016-08-24 14:45:40, 2012-01-01 02:07:31, 2012-01-01 21:53:26, 2012-01-01 23:04:56, 2012-01-06 20:14:52, 2012-01-06 21:14:58
metadatatimeend 2016-08-08 21:04:11, 2016-08-09 08:25:36, 2016-08-09 11:09:48, 2016-08-16 10:32:19, 2016-08-16 11:06:35, 2016-08-17 14:44:44, 2016-08-22 09:24:43, 2012-01-06 20:52:59, 2012-01-07 19:01:49, 2012-01-07 19:04:31
start_time 09:00:00.000+02, 08:30:00.000+02, 09:40:00.000+02, 10:13:00.000+02, 10:36:00.000+02, 12:20:00.000+02, 09:14:00.000+02, 09:29:00.000+02, 10:14:00.000+02, 10:56:00.000+02
date 2016-08-10, 2016-08-11, 2016-08-08, 2016-08-17, 2016-08-03, 2016-08-18, 2016-08-22, 2016-08-19, 2016-08-04, 2016-08-12
enum_name Hagenimana bienvenue, MUCYOWIMIHIGO J MV, Nyandwi Anathalie, ZIMUKWIYE Dominique, Nyirangirimana jeanne, Torero pacifique, Utamuriza Jeanne, Niyidufasha nathanael, Rukundo japhet, NYIRAMPANO Bernadette
photo NA, 1325376816129.jpg, 1325447804135.jpg, 1325452024080.jpg, 1325873951716.jpg, 1325877535600.jpg, 1325891580194.jpg, 1469601919598.jpg, 1469601990645.jpg, 1469602247216.jpg
district Rutsiro, Karongi, Mugonero, Nyamasheke, Huye, Rwamagana, Gatsibo_NLWH, Gatsibo_LWH, Nyamagabe, Kayonza
cell_field Rubumba, Mubuga, Nyabicwamba, NYAGATARE, Mugera, MutongoCA, Bihumbe, Busetsa, Gihumuza, Kibyagira A
village Gasharu, Murambi, Rugarama, Kabeza, Karambo, Kigarama, Nyabugogo, Kabuga, Kivumu, Gasagara
farmer_list Havugimana celestin, Karekezi Celestin, Mukabinyange cecile, Mukafundi Marie, Musabyimana Jean, Ndananiwe Francois, Ndayambaje Emmanuel, Nsengiyumva Augustin, Nyirahabimana seraphine, Nyiraminani Constasie
farmer_respond NA, Akimana Jeannette, BIMENYANDE Djumapri, Habimana Emmanuel, Hagumagatsi Gaspard, Karekezi Celestin, Mukabinyange cecile, Mukangiriye Donatha, Mukankusi Beatrice, MUNYENSANGA Emmanuel
farmer_phonenumber NA, Ntayo, 0, ntayo, Nta telephone afite, Ntayo afite, 0.0, -, nta telephone afite, Ntayo bafite
d_phone NA, 0, Ntayo, ntayo, Ni wewabajijwe, -, Ntayo afite, O, Nta telephone afite, Ntayo bafite
neighbor_phonenumber NA, ntayo, 0, Ntayo, 0.0, -, 0789699430, 0785275883, 7.85275883E8, 0723071668
gender female, male
n_tubura_season not_a_client_3seasons, 16a 16b 17a, 16a 17a, 17a, 16a 16b, 16a, NA, 16b 17a, 16b, 16a not_a_client_3seasons
which_crop_16a_1 gor
which_maize_seed_16a_1 NA, gor_nsp, new_hybrid, OPV_saved, Hybride_saved, OPV_new
which_crop_16a_2 NA, yum, gor, big, insina, jum, soya, ray, shy, shaz
which_maize_seed_16a_2 NA, gor_nsp, Hybride, OPV_saved, OPV_new, Hybride_saved
fert_type1_16a None, DAP, NA, NPK-17, urea, NPK-22, npk2555
fert_type2_16a NA, urea, None, DAP, NPK-17, NPK-22, npk2555
quality_compost_16a Good, NA, Average, Bad
type_compost_16a cow, NA, goat, pig, other, plant, kitchen_waste, human, chicken
d_lime_16a no_lime, NA, lime_outside, lime_tubura, both_tubura_non_tubura
which_crop_16b_1 big, shy, saka, NA, jum, soya, gor, ray, nyo, yum
which_maize_seed_16b_1 NA, new_hybrid, gor_nsp, OPV_new, Hybride_saved, OPV_saved
which_crop_16b_2 NA, gor, yum, jum, insina, big, soya, saka, shy, ray
which_maize_seed_16b_2 NA, new_hybrid, OPV_new, gor_nsp, Hybride_saved, OPV_saved
fert_type1_16b None, NA, DAP, NPK-17, urea, NPK-22, npk2555
fert_type2_16b NA, None, urea, DAP, NPK-17
quality_compost_16b NA, Good, Average, Bad
type_compost_16b NA, cow, pig, goat, kitchen_waste, plant, human, other, chicken
d_lime_16b no_lime, NA, lime_outside, lime_tubura
how_use_residues feed_animals, mulching, leave_field, compost_use, burn_field, burn_discard, sell
field_texture clay_loam, loam, silty_clay_loam, sandy_clay_loam, sandy_loam, silty_loam, silty_clay, loamy_sand, sand, clay
field_erosion drainageditch, nothing, radicalterrace, gradualterrace
crop_direction not_applicable, NA, across_slope, down_slope
comments Ntakibazo, ntakibazo, ntayo, Ntayo, Ntazo, ntazo, Ntakibazo., Ntacyahindutse, NA, No comments
sample_id 12, 1503, 2044C, 2278, 2299, 2610, 2612, 2612C, 10, 1001
kg_yield_hwag_16b_1 NA
kg_seed_ananas_16b_2 NA
kg_seed_veg_16a_1 NA
kg_seed_16a_1 N, 1, 0, 2, -, 3, 4, 5, 6, 8
kg_seed_16a_2 , NA, 0.5, 1, 0.25, 2, 3, 1.5, 4, 5
kg_seed_16b_1 NA, , 3, 2, 1, 0.5, 1.5, 4, 5, 6
kg_seed_16b_2 , NA, 0.5, 1, 0.25, 2, 1.5, 3, 4, 5
kg_yield_16a_1 NA, 50, 20, 100, 30, 10, 40, 15, 200, 5
kg_yield_16a_2 , NA, 20, 10, 50, 30, 0, 15, 5, 100
kg_yield_16b_1 , NA, 20, 30, 10, 15, 5, 50, 40, 100
kg_yield_16b_2 , NA, 0, 10, 5, 20, 15, 3, 40, 50
gps_coord NA, -1.5578864555610237 30.39436791689242 1525.93 15.0, -1.5631940702424174 30.227211802604916 1659.67 15.0, -1.5639320092237632 30.227385933820276 1434.79 10.0, -1.5667398240763533 30.273551799148027 979.26 10.0, -1.567033053159622 30.277914044142907 982.39 10.0, -1.5671285398447943 30.275353919885177 560.94 10.0, -1.5685424850437755 30.248542080122405 1468.14 20.0, -1.5688621725334673 30.24841864727349 851.74 10.0, -1.5693591302006047 30.23708561051914 1366.33 10.0
unique_location Gatsibo_NLWH2610, Gatsibo_NLWH2612, Gatsibo_NLWH2612C, Karongi1503, Rutsiro2044C, Rutsiro2278, Rutsiro2299, Gatsibo_LWH2476, Gatsibo_LWH2476C, Gatsibo_LWH2478

4.2.2 Categorical response graphs

repGraphs <- function(dat, x){
  tab = as.data.frame(table(dat[,x], useNA = 'ifany'))
  tab = tab[order(tab$Freq, decreasing = T),]
  print(
    ggplot(data=tab, aes(x=Var1, y=Freq)) + geom_bar(stat="identity") +
      theme(legend.position = "bottom", axis.text.x = element_text(angle = 45, hjust = 1)) +
      labs(title =paste0("Composition of variable: ", x))
  )
}
adminVars <- c(names(r)[grep("meta", names(r))], "start_time", "enum_name", "photo", "cell_field", "village", "farmer_respond", "farmer_phonenumber", "d_phone", "neighbor_phonenumber", "farmer_list", "unique_location", "comments", "gps_coord", "sample_id", "SSN")
nonAdminVars <- catVars[!catVars %in% adminVars]
for(i in 1:length(nonAdminVars)){
  repGraphs(r, nonAdminVars[i])
}

4.2.3 Manual character cleaning

r$female <- ifelse(r$gender=="female", 1, 0)
r$district <- ifelse(grepl("nyanza", r$district)==T, "Nyanza", r$district)
#table(r$kg_seed_16b_1)
#table(r$kg_yield_16a_2)
strtoNum <- c("kg_seed_16b_1", "kg_yield_16a_1", "kg_yield_16b_1", "kg_yield_16b_2")
r[,strtoNum] <- sapply(r[,strtoNum], function(x){as.numeric(x)})

4.2.4 Categorical cleaning

TODO here!

Notes on the categorical variables:

  • We don’t have many actual responses on seed type despite all farmers telling us about a crop they are growing. Why? Check that there wasn’t a mislabeling of variables.
  • Check the ‘which_maize_seed’ variables to make certain they’re flexible to the type of crop selected in the previous question.
  • Confirm that blank is NA not 0.

4.3 Numeric variables

numVars <- names(r)[sapply(r, function(x){
  is.numeric(x)
})]

Basic cleaning of known issues like enumerator codes for DK, NWR, etc.

enumVals <- c(-88,-85, -99)
r[,numVars] <- sapply(numVars, function(y){
  r[,y] <- enumClean(r,y, enumVals)
})

4.3.1 Numeric outlier table

iqr.check <- function(dat, x) { 
  q1 = summary(dat[,x])[[2]]
  q3 = summary(dat[,x])[[5]] 
  iqr = q3-q1
  mark  = ifelse(dat[,x] < (q1 - (1.5*iqr)) | dat[,x] > (q3 + (1.5*iqr)), 1,0)
  tab = rbind(
    summary(dat[,x]),
    summary(dat[mark==0, x])
  )
  return(tab)
}
# remove admin vars
numAdminVars <- c(numVars[1:3])
numVarsNotAdmin <- numVars[!numVars %in% numAdminVars]
iqrTab <- do.call(plyr::rbind.fill, lapply(numVarsNotAdmin, function(y){
  #print(y)
  res = iqr.check(r, y)
  #print(dim(res))
  out = data.frame(var=rbind(y, paste(y, ".iqr", sep="")), res)
  return(out)
}))
iqrTab[,2:8] <- sapply(iqrTab[,2:8], function(x){round(x,1)})

The outlier table summarizes the numeric variables with and without IQR outliers to show how the data changes based on this filter.

knitr::kable(iqrTab, row.names = F, digits = 0, format = 'markdown')
var Min. X1st.Qu. Median Mean X3rd.Qu. Max. NA.s
d_client_16b 0 0 0 0 1 1 NA
d_client_16b.iqr 0 0 0 0 1 1 NA
d_client_17a 0 0 0 0 1 1 NA
d_client_17a.iqr 0 0 0 0 1 1 NA
age 16 35 45 47 57 90 NA
age.iqr 16 35 45 47 57 90 NA
n_household 0 4 5 5 7 39 NA
n_household.iqr 0 4 5 5 7 11 NA
n_cows 0 0 1 1 1 15 NA
n_cows.iqr 0 0 1 1 1 2 NA
n_goats 0 0 0 1 2 18 NA
n_goats.iqr 0 0 0 1 2 5 NA
n_chickens 0 0 0 1 1 40 NA
n_chickens.iqr 0 0 0 0 0 2 NA
n_pigs 0 0 0 0 1 11 NA
n_pigs.iqr 0 0 0 0 1 2 NA
n_sheep 0 0 0 0 0 35 NA
n_sheep.iqr 0 0 0 0 0 0 NA
field_length 0 13 20 26 32 214 NA
field_length.iqr 0 13 20 23 30 60 NA
field_width 0 12 20 24 31 160 NA
field_width.iqr 0 12 20 22 30 59 NA
n_spots 3 3 3 4 5 5 NA
n_spots.iqr 3 3 3 4 5 5 NA
fert_kg1_16a 0 1 2 4 5 80 1408
fert_kg1_16a.iqr 0 1 2 3 4 11 1408
fert_kg2_16a 0 0 0 2 2 200 1198
fert_kg2_16a.iqr 0 0 0 1 2 5 1198
d_compost_16a 0 1 1 1 1 1 271
d_compost_16a.iqr 1 1 1 1 1 1 271
kg_compost_16a 0 100 200 268 300 20000 613
kg_compost_16a.iqr 0 100 191 205 300 600 613
kg_lime_16a 0 15 40 66 100 500 2345
kg_lime_16a.iqr 0 10 25 52 100 150 2345
fert_kg1_16b 0 1 2 4 4 100 1964
fert_kg1_16b.iqr 0 1 2 2 3 8 1964
fert_kg2_16b 0 0 0 0 0 88 1656
fert_kg2_16b.iqr 0 0 0 0 0 0 1656
d_compost_16b 0 0 1 0 1 1 529
d_compost_16b.iqr 0 0 1 0 1 1 529
kg_compost_16b 0 100 160 238 300 10000 1411
kg_compost_16b.iqr 0 100 150 193 250 600 1411
kg_lime_16b 1 10 25 59 50 650 2353
kg_lime_16b.iqr 1 10 25 32 50 100 2353
field_slope -5 3 6 9 14 60 NA
field_slope.iqr -5 3 6 9 14 30 NA
field_n_crops 0 1 1 2 2 30 343
field_n_crops.iqr 0 1 1 1 2 3 343
kg_seed_16b_1 0 1 2 5 4 500 754
kg_seed_16b_1.iqr 0 1 2 3 4 10 754
kg_yield_16a_1 0 15 34 73 80 6000 1570
kg_yield_16a_1.iqr 0 12 30 41 50 170 1570
kg_yield_16b_1 0 8 20 53 50 6000 600
kg_yield_16b_1.iqr 0 8 20 28 40 112 600
kg_yield_16b_2 0 3 10 25 25 600 1954
kg_yield_16b_2.iqr 0 3 8 13 20 55 1954
yield_compare_16a_1 1 1 1 2 3 3 1506
yield_compare_16a_1.iqr 1 1 1 2 3 3 1506
yield_compare_16a_2 1 1 2 2 2 3 1355
yield_compare_16a_2.iqr 1 1 2 2 2 3 1355
yield_compare_16b_1 1 1 1 2 2 3 358
yield_compare_16b_1.iqr 1 1 1 2 2 3 358
yield_compare_16b_2 1 1 1 2 2 3 1734
yield_compare_16b_2.iqr 1 1 1 2 2 3 1734
lat -3 -2 -2 -2 -2 -2 497
lat.iqr -3 -2 -2 -2 -2 -2 497
lon 29 29 30 30 30 31 497
lon.iqr 29 29 30 30 30 31 497
alt -108 1513 1673 1668 1887 2668 497
alt.iqr 957 1541 1680 1728 1887 2430 497
precision 5 10 15 19 15 4181 497
precision.iqr 5 10 15 13 15 20 497
female 0 0 1 1 1 1 NA
female.iqr 0 0 1 1 1 1 NA

4.3.2 Outlier Graphs

# http://rforpublichealth.blogspot.com/2014/02/ggplot2-cheatsheet-for-visualizing.html
for(i in 1:length(numVarsNotAdmin)){
    base <- ggplot(r, aes(x=r[,numVarsNotAdmin[i]])) + labs(x = numVarsNotAdmin[i])
    temp1 <- base + geom_density()
    temp2 <- base + geom_histogram()
    #temp2 <- boxplot(r[,numVars[i]],main=paste0("Variable: ", numVars[i]))
    multiplot(temp1, temp2, cols = 2)
}

4.3.3 Numeric variable cleaning

TODO here!

4.4 Merge in soil data

First merge the soil data with the identifiers as we should get full matches. Then merge soil data to the survey data

Identifiers <- Identifiers %>% rename(
  sample_id = `Sample ID`,
  SSN = `Lab ssn`
) %>% mutate(
  sample_id = gsub(" ", "", tolower(sample_id))
)
table(Identifiers$SSN %in% soil$SSN) # full matches

TRUE 
2426 
soil <- left_join(soil, Identifiers[, c("SSN", "sample_id")], by="SSN") 

We have some surveys that don’t have soil data. It seems the soil sample id in the Identifiers data are a bit messy. Let’s clean both up above by removing spaces and making lower case.

r$sample_id <- tolower(r$sample_id)
table(r$sample_id %in% soil$sample_id)

FALSE  TRUE 
   28  2366 
r$sample_id[!r$sample_id %in% soil$sample_id]
 [1] "1062c" "1198c" "1212"  "1228"  "1242"  "1380c" "1384c" "1626c" "204"   "2042c"
[11] "2175"  "2415"  "2418"  "2418c" "2426"  "2426c" "2534"  "2561c" "2636c" "2671c"
[21] "2696"  "2741"  "2819"  "2979"  "596c"  "65c"   "66c"   "931"  
write.csv(r$sample_id[!r$sample_id %in% soil$sample_id], "surveysWoSoil.csv", row.names = F)

And some soil sample_id that don’t have a survey

soil$sample_id[!soil$sample_id %in% r$sample_id]
 [1] "569c"  "902"   "902c"  "903"   "903c"  "904"   "904c"  "909"   "909c"  "912"  
[11] "912c"  "931c"  "946"   "946c"  "947"   "947c"  "953"   "953c"  "954"   "954c" 
[21] "962"   "962c"  "964"   "966c"  "967"   "968c"  "969c"  "970"   "970c"  "971"  
[31] "971c"  "973"   "975"   "975c"  "1061c" "1062"  "1096"  "1096c" "1102"  "1102c"
[41] "1103"  "1103c" "1105"  "1105c" "1159"  "1159c" "1162c" "1203"  "1359"  "1372" 
[51] "1432c" "1437"  "1501"  "1503c" "1538"  "2215"  "2204"  "2350c" "2355"  "2368" 
[61] "2625c" "956c"  "2685c" "2819c" "2634"  "2850c" "1189c"
write.csv(soil$sample_id[!soil$sample_id %in% r$sample_id], "soilsWoSurvey.csv", row.names = F)
dim(r)
[1] 2394   93
r <- left_join(r, soil, by="sample_id")
dim(r) # why is it one row longer after the left_join?
[1] 2395  115

4.5 Soil values

ggplot(r, aes(x=Calcium, y=Magnesium)) + geom_point() +
    stat_smooth(method="loess") +
    labs(x = "Calcium (m3)", y= "Magnesium (m3)", title="Calcium and Magnesium relationship")

ggplot(r, aes(x=pH, y=Calcium)) + geom_point() +
  stat_smooth(method="loess") +
  labs(x = "pH", y="Calcium (m3)", title = "pH and Calcium relationship")

ggplot(r, aes(x=pH, y=Magnesium)) + geom_point() +
  stat_smooth(method="loess") +
  labs(x = "pH", y="Magnesium (m3)", title = "pH and Magnesium relationship")

ggplot(r, aes(x=pH, y=X.Exchangeable.Acidity)) + geom_point() +
  stat_smooth(method="loess") +
  labs(x = "pH", y="Exchangeable Aluminum", title = "pH and Aluminum relationship")

ggplot(r, aes(x=X.Organic.Carbon, y=X.Total.Nitrogen)) + geom_point() + 
  stat_smooth(method="loess") +
  labs(x = "Total Carbon", y="Total Nitrogen", title = "Carbon and Nitrogen relationship")

ggplot(r, aes(x=pH, y=X.Exchangeable.Acidity)) + geom_point() + 
  stat_smooth(method="loess") +
  scale_x_continuous(breaks=seq(4,8,0.5)) +
  labs(x = "pH", y="Exchangeable Acidity", title = "pH / ExAc")

soilVars <- names(r)[which(names(r)=="pH"):which(names(r)=="X.Total.Nitrogen")]
keySoilVars <- c("pH", "X.Organic.Carbon", "X.Total.Nitrogen", "Calcium", "Magnesium")
write.csv(soilVars, file="soilVarsforStep.csv", row.names = F)

4.5.1 Initial T vs. C soil comparison

Please note: These are raw comparisons using only round 1 data and thus should not be taken as initial findings for how T and C farmers compare. Farmers will be matched to ensure a proper comparison.

for(i in 1:length(soilVars)){
  p1 <- ggplot(data=r, aes(x=as.factor(d_client_16b), y=r[,soilVars[i]])) + 
    geom_boxplot() +
    labs(x="Tubura Farmer", y=soilVars[i])
  p2 <- ggplot(data=r, aes(x=r[,soilVars[i]])) + 
    geom_density() + 
    labs(x=soilVars[i])
  multiplot(p1, p2, cols=2)
}

4.5.2 Soil notes for Patrick and Step

  • The carbon vs. nitrogen scatter plot looks odd in that the values are clumped in discrete lines. Why might that be?
  • What are appropriate cutoff values for the lab predictions? (Patrick, as a general question, we should probably apply those cutoffs to any lab data before sharing it with the teams to simplify working with those data)

4.5.3 Soil value cleaning

Step and Patrick say that it’s hard to set hard and fast guidelines for what are and are not reasonable values. I’m therefore going to see what happens to the data if we trim by sd and IQR and then apply one of those adjustments to the data.

check.3sd <- function(x) {
  x = ifelse(is.infinite(x), NA, x)
  mean = mean(x, na.rm=T)
  sd = sd(x, na.rm=T)
  mark = ifelse(x>(mean + (3*sd)) |
        x<(mean - (3*sd)), NA, x)
  return(mark)
}
sdSoilVals <- r %>%
  dplyr::select(pH:X.Total.Nitrogen) 
sdCheck <- as.data.frame(apply(sdSoilVals, 2, function(x){
  return(check.3sd(x))
}))
for(i in 1:length(soilVars)){
  print(ggplot(data=sdCheck, aes(x=sdCheck[,soilVars[i]])) + 
    geom_density() + 
    labs(x=soilVars[i])
  )
}

Important note: I’m going to add the adjusted values to the r data frame giving the previous variables the extension .raw so I can distinguish between the original and modified data.

names(r)[which(names(r)=="pH"):which(names(r)=="X.Total.Nitrogen")] <- paste0(names(r)[which(names(r)=="pH"):which(names(r)=="X.Total.Nitrogen")], ".raw")
r <- cbind(r, sdCheck)

4.6 Check for unique ids

I’m seeing that there are duplicated farmers in the data when I’m trying to reshape the r data from wide to long. Let’s check them out here and see if we can figure out which observation is right.

  • Check Alex’s do file to see if there’s mention of these farmers. [No mention]
  • Check the baseline values as these should line up.
length(r$sample_id)==length(unique(r$sample_id))
[1] FALSE
dups <- r$sample_id[duplicated(r$sample_id)]
dupIndex <- which(duplicated(r$sample_id))
#dupDat <- r[r$sample_id %in% dups,]
#head(r[r$sample_id==dups[1],])
#head(r[r$sample_id==dups[2],])

Let’s solve the unique id issue by looking at identifying information in the baseline data

roundId <- r %>%
  dplyr::select(district, cell_field, village, sample_id, farmer_list) %>%
  filter(r$sample_id %in% dups)
#d
load("rawBaselineWithIdentifers.Rdata")
baseId <- d %>% 
  dplyr::select(district, selected_cell, umudugudu,  sample_id, farmer_name ) %>%
  filter(d$sample_id %in% dups)
#baseId
#roundId

4.6.1 Correct duplicates

Correct the duplicates I can and drop the others for now. Flag the duplicated ones and save them to share with Nathaniel.

TODO(mattlowes) - share any remaining duplicates with Nathaniel and see if he has a solution. Also see if he can understand why this might have happened and if they should actually have a different sample id.

  • share the merged data for Nathaniel to put into CC (include the duplicate ids)
r <- r %>% mutate(
    dup = ifelse(
      sample_id == "12" & cell_field == "MUNANIRA" |
      sample_id == "137" & village == "Rusuma" |
      sample_id == "1503" & farmer_list=="NAKAGIZE Val\\xc3\\xa9rie" |
      #sample_id == "2044C" &  # same!
      sample_id == "2278" & cell_field=="Nkira A" | # check this as maybe this was the only thing wrong?
      #sample_id == "2299" & # same!
      sample_id == "2610" & village=="agakiri" #|  #agakiri is close to gakiri in spelling. Is this just a typo?
      #sample_id == "2612" &  # same names!
      #sample_id == "2612C" # same names!
      , 1, 0)
) %>% filter(
  dup!=1
) %>% dplyr::select(-dup) 
# run this code again from above to get updated duplicates list
#length(r$sample_id)==length(unique(r$sample_id))
dups <- r$sample_id[duplicated(r$sample_id)]
dupIndex <- which(duplicated(r$sample_id))
# for the time being drop the observations that are duplicates
r <- r[!r$sample_id %in% dups,]

4.7 Reshape variables

This should include the baseline variables as well.

Let’s first check with the baseline data to see what variables we made there so I can make the same ones from the round 1 data. There are some variables that are baseline variables only like variables asking about historical practices. There are then other variables that will vary by season. These are the variables that we ultimately want in to shape in a long dataset by season to analyze changes overtime in practices and soil management. I think this will result in a dataset that has one row per farmer per season. Some variables may not fit nicely into this but we can deal with those. For variables that aren’t changing over time they’ll show as not important in our model. They’re important for matching farmers.

There are a lot of variables to try to line up. Some already have the same name but how to best combine the ones that have different variable names? I’m going to write a function that takes a variable name from b and a variable name from r that should go together, updates the r variable name and uses that info to rbind the data into a long dataset.

# names(b)
# names(r)
# check the names that already match
baselineFound <- names(b)[names(b) %in% names(r)] # not many variable names are aligned

Update variable names so that any variable with 16a or 16b has a the a or b season designation at the end it so I can replicate the gather() and spread() options for reorganizing the data by season and by plot. This means that the variable names will retain their designation of first or second application and be distinguishable.

TODO(mattlowes) - rename the variables according to that convention to reshape the r data. Keep the baseline data in mind as we’ll want to do the same thing with the baseline data to make them match.

r <- r %>% rename(
  which_crop_1_16a = which_crop_16a_1,
  which_maize_seed_1_16a = which_maize_seed_16a_1,
  which_crop_2_16a = which_crop_16a_2,
  which_maize_seed_2_16a = which_maize_seed_16a_2,
  kg_seed_veg_1_16a = kg_seed_veg_16a_1,
  kg_seed_1_16a = kg_seed_16a_1,
  kg_seed_2_16a = kg_seed_16a_2,
  kg_yield_1_16a = kg_yield_16a_1,
  kg_yield_2_16a = kg_yield_16a_2,
  yield_compare_1_16a = yield_compare_16a_1,
  yield_compare_2_16a = yield_compare_16a_2,
  
  which_crop_1_16b = which_crop_16b_1,
  which_maize_seed_1_16b = which_maize_seed_16b_1,
  which_crop_2_16b = which_crop_16b_2,
  which_maize_seed_2_16b = which_maize_seed_16b_2,
  #kg_seed_veg_1_16a = kg_seed_veg_16a_1,
  #kg_seed_ananas_2_16a = kg_seed_ananas_16a_2,
  #kg_seed_hwag_1_16a = kg_seed_hwag_16a_1,
  kg_seed_1_16b = kg_seed_16b_1,
  kg_seed_2_16b = kg_seed_16b_2,
  kg_yield_1_16b = kg_yield_16b_1,
  kg_yield_2_16b = kg_yield_16b_2,
  yield_compare_1_16b = yield_compare_16b_1,
  yield_compare_2_16b = yield_compare_16b_2
)
aSeason <- names(r)[grep("(1.a)", names(r))]
bSeason <- names(r)[grep("(1.b)", names(r))]
seasonalVars <- c(aSeason, bSeason, "sample_id")
farmerVars <- c(names(r)[!names(r) %in% seasonalVars], "sample_id")
# example data
# df <- data.frame(
#   id = 1:10,
#   time = as.Date('2009-01-01') + 0:9,
#   Q3.2.1. = rnorm(10, 0, 1),
#   Q3.2.2. = rnorm(10, 0, 1),
#   Q3.2.3. = rnorm(10, 0, 1),
#   Q3.3.1. = rnorm(10, 0, 1),
#   Q3.3.2. = rnorm(10, 0, 1),
#   Q3.3.3. = rnorm(10, 0, 1)
# )
# 
# df %>%
#   gather(key, value, -id, -time) %>%
#   extract(key, c("question", "loop_number"), "(Q.\\..)\\.(.)") %>%
#   spread(question, value)
# aDat <- r[,names(r) %in% aSeason] # works for this too!
# aDat <- aDat[,grep("16a_1", names(aDat))] # works for this
aDat <- r[,names(r) %in% seasonalVars] # works for this!
#http://stackoverflow.com/questions/25925556/gather-multiple-sets-of-columns
seasonalDat <- aDat %>%
  gather(key, value, -sample_id) %>%
  tidyr::extract(key, c("variable", "season"), "(^.*\\_1.)(.)") %>%
  mutate(season = paste0("16", season)) %>% 
  spread(variable, value)
names(seasonalDat) <- gsub("_16", "", names(seasonalDat))

TODO(mattlowes) - confirm that the tidyr process worked as I expected as there are numerous missing values. These seem to appear where the variable only had one version of the variable, _16, rather than a _16a and a _16b. Check out how this is handling variables with _17 instead of _16.

4.8 Merge seasonal and demographic data

rs <- left_join(seasonalDat, r[,c(names(r)[!names(r) %in% seasonalVars],"sample_id")], by="sample_id")

4.9 Combine long with baseline

The matchRounds function updates variable names across rounds and reports the index and new name of the variables. I can then take the first part of the list for dat1 and the second part for dat2.

Or just change baseline variable names manually. What’s the best way to do this? First reshape the baseline variables to be plot level as well with a season indicator.

TODO(matt.lowes) Confirm that this is necessary. If the baseline data only includes the previous season and the history then the reshape may not be necessary. All subsequent surveys asked about two seasons, the intervening season and the relevant season. Get your head around the baseline data again and act.

# b <- b %>% rename(
#   inputuse_priord_fertilizer_15b = inputuse_15b_priord_fertilizer,
#   inputuse_priorculture_15b_1 = inputuse_15b_priorculture_15b_1,
#   inputuse_priord_intercrop_15b = inputuse_15b_priord_intercrop_15b,
#   inputuse_priorculture_in_15b = inputuse_15b_priorculture_15b_in,
#   crop1_seety_15b = crop1_15b_seedty,
#   #v58
#   crop1_yield_15b = crop1_15b_yield,
#   crop1_yield__15b = crop1_15b_yield_,
#   crop2_seedty_15b = crop2_15b_seedty,
#   #63
#   crop2_seedkg_15b = crop2_15b_seedkg,
#   crop2_yield_16b = crop2_15b_yield,
#   crop2_yield__15b = crop2_15b_yield_,
#   field_fert_t_15b = field_15b_fert_t,
#   #v69
#   field_compost_qu_15b = field_compost_qu
# )

I think that all needs to be done is to add a season variable and rename the baseline variables to take off the _15b portion.

write.csv(names(b), "baselineVars.csv", row.names = T)
write.csv(names(rs), "round1Vars.csv", row.names = T)
names(b) <- gsub("_15b", "", names(b))
b$season <- "15b"
b <- b %>% rename(
      crop1_local = v58,
      crop2_local = v63,
      field_fert_t_1 = field_fert_t,
      field_fert_t_2 = v69
    )

TODO - it also seems to the case that some of the seed type variables are mixed up in r and rs. See what the issue is. Each plot should have only one answer for those.

MAJOR TODO: confirm that I’m not duplicating the soil data by assigning it to both of the seasons we asked about in the follow up survey (I think I currently am 6/15/17). We want to account for field management in the intervening season but we don’t want to assume the soil outcome is the same for both seasons. Specifically, this means the 16a season

TODO - add the onlyR1 variables back into the data so we have field texture.

Note: the final long data by plot should have only one observation for stationary variables like slope or historical information

# i'm updating baseline names to match round 1 names. 
bUpdate <- b %>% 
  mutate(
    d_compost = ifelse(field_kg_compost > 0, 1, 0)
  ) %>%
  rename(
  tablet = demographicid_tablet,
  village = umudugudu,
  n_household = hhsize,
  n_tubura_season = total.seasons,
  field_length = field_dim1, # I'm assuming dim1 is length. it might not be. It might not matter.
  field_width = field_dim2,
  n_spots = n_spots_c,
  kg_seed_1 = crop1_seedkg,
  kg_seed_2 = crop2_seedkg,
  fert_kg1 = field_kg_fert1,
  fert_kg2 = field_kg_fert2,
  kg_yield_1 = crop1_yield,
  kg_yield_2 = crop2_yield,
  kg_compost = field_kg_compost,
  d_client = client,
  cell_field = cellule_field,
  fert_type1 = field_fert_t_1,
  fert_type2 = field_fert_t_2,
  X.Total.Nitrogen = Total.Nitrogen,
  X.Sodium = Sodium,
  X.Organic.Carbon = Organic.Carbon,
  X.EC..Salts. = EC..Salts.,
  X.C.E.C = C.E.C,
  X.Exchangeable.Acidity = Exchangeable.Acidity,
  X.Exchangeable.Aluminium = Exchangeable.Aluminium,
  X.Phosphorus.Sorption.Index..PSI. = Acid.Saturation, # check that this is right
  n_cows = betail_ownedn_inka,
  n_goats = betail_ownedn_ihene,
  n_chickens = betail_ownedn_inkoko,
  n_pigs = betail_ownedn_ingurube,
  n_sheep = betail_ownedn_intama,
  date = demographicdate,
  field_slope = general_field_infograde_hill,
  field_erosion = general_field_infoantierosion_ef,
  type_compost = field_type_compo,
  quality_compost = field_compost_qu,
  d_sample = sample,
  enum_name = surveyor,
  how_use_residues = action_cropresid
)
# biographical variales that apply to actions in the baseline before the study started
bioVars <- bUpdate %>% dplyr::select(
  n_season_fert, nofert_why, n_season_compost, nocompost_why, n_season_lime, nolime_why,
  n_season_fallow, n_seasons_leg_1, n_seasons_leg_2, aez, contains("d_season_listd_"),
  contains("inputuse_prior")
)
bVars <- names(bUpdate)[!names(bUpdate) %in% names(bioVars)] # remove biographical vars
# organizational variables to be ignored
orgVars <- bUpdate %>%
  dplyr::select(
    fieldcollectiondate, datecollectedindistrict, datesenttohq, datereceivedathq,
    processedathq_, packedforsendingtokenya_, datefinishedprocessing
  )
bVars <- bVars[!bVars %in% names(orgVars)]
# variables that only appear in the round 1 data >> likely want to keep these and make them part of the "stable" identifying data
onlyR1 <- rs %>%
  dplyr::select(
    field_n_crops, crop_direction, field_texture, sample_id
  )
r1Vars <- names(rs)[!names(rs) %in% names(onlyR1)]
# check what's already the same
matchNames <- r1Vars[r1Vars %in% bVars] # these are the matches we're getting
# matchNames
# check what isn't accounted for somehow
unmatchedB <- bVars[!bVars %in% r1Vars] # unmatched baseline minus demographic vars
unmatchedRs <- r1Vars[!r1Vars %in% bVars] # unmatched r1

Make the sample id lower case

bUpdate$sample_id <- tolower(bUpdate$sample_id)
rs$sample_id <- tolower(rs$sample_id)

4.10 Merge demographic variables

  • Identify demographic and historical variables in b
  • Identify any new data from R1 not in the baseline and merge them in
  • I’m using bUpdate as it’s the most up to date and simplifies updating the script.
bDemo <- bUpdate %>% 
  dplyr::select(
  SSN, district, cell_field, village, sample_id,  
  n_season_fert, nofert_why, n_season_compost, nocompost_why, n_season_lime, nolime_why,
  n_season_fallow, n_seasons_leg_1, n_seasons_leg_2, aez, contains("d_season_listd_"),
  contains("inputuse_prior")
)

4.11 Append field/soil variables

  • rbind R1 field level variables with b field level variables to make a plot level dataset.
  • Select only the variables I want to keep
  • Generate any new outcomes that bring the data down to a single outcome, rather than one by plot and season.
  • I can then make longitudinal outcomes from those data and merge those into the demographic data
  • Put in variable here that marks whether the farmer retained their treatment status from the baseline
commonVars <- names(rs)[names(rs) %in% names(bUpdate)] # using rs because i changed the baseline names to match the rs names
write.csv(commonVars, file="varNamesforM&E.csv")
fieldDat <- rbind(bUpdate[,commonVars], rs[,commonVars]) # combine baseline and round 1
# add back in the onlyR1 variables that we want to have

soilDat is the object that has the soil variables for soil specific analyses. You can get to field observations with soil observations by dropping the A season data points.

soilDat <- fieldDat %>% 
  dplyr::select(one_of(soilVars), SSN, season, sample_id, d_client) %>%
  filter(season!="16a") # dropping the 16a values as these aren't true measurements but a result of reshaping the round 1 data.
fieldSoilDat <- fieldDat %>%
  filter(season!="16a")

fieldDat is all seasons including 16a for which we don’t have separate soil observations fieldSoilDat is only 15b and 16b for which we have soil observations.

4.12 Create new variables

4.12.1 Field variables

I originally made these new outcomes for just the round 1 data but I really want to have common outputs for plots by seasons that I can then turn into longitudinal outcomes.

fieldSoilDat$dim <- fieldSoilDat$field_length * fieldSoilDat$field_width
fieldSoilDat$are <- fieldSoilDat$dim/100
inputVars <- names(fieldSoilDat)[grep("fert_|quality_compost|type_compost|which_crop|which_maize", names(fieldSoilDat))]
fieldSoilDat[,inputVars] <- sapply(fieldSoilDat[, inputVars], tolower)
# input quanitites
fieldSoilDat$fert_kg_urea1 <- ifelse(fieldSoilDat$fert_type1=="urea", fieldSoilDat$fert_kg1, NA)
fieldSoilDat$fert_kg_urea2 <- ifelse(fieldSoilDat$fert_type2=="urea", fieldSoilDat$fert_kg2, NA)
fieldSoilDat$fert_total_urea <- apply(fieldSoilDat[, grep("(urea.)", names(fieldSoilDat))], 1, function(x){
  sum(as.numeric(x), na.rm=T)})
fieldSoilDat$fert_kg_dap1 <- ifelse(fieldSoilDat$fert_type1=="dap", fieldSoilDat$fert_kg1, NA)
fieldSoilDat$fert_kg_dap2 <- ifelse(fieldSoilDat$fert_type2=="dap", fieldSoilDat$fert_kg2, NA)
fieldSoilDat$fert_total_dap <- apply(fieldSoilDat[, grep("(dap.)", names(fieldSoilDat))], 1, function(x){
  sum(as.numeric(x), na.rm=T)})
fieldSoilDat$fert_kg_17npk1 <- ifelse(fieldSoilDat$fert_type1=="npk-17", fieldSoilDat$fert_kg1, NA)
fieldSoilDat$fert_kg_17npk2 <- ifelse(fieldSoilDat$fert_type2=="npk-17", fieldSoilDat$fert_kg2, NA)
fieldSoilDat$fert_total_17npk <- apply(fieldSoilDat[, grep("(17npk.)", names(fieldSoilDat))], 1, function(x){
  sum(as.numeric(x), na.rm=T)})
fieldSoilDat$fert_kg_22npk1 <- ifelse(fieldSoilDat$fert_type1=="npk-22", fieldSoilDat$fert_kg1, NA)
fieldSoilDat$fert_kg_22npk2 <- ifelse(fieldSoilDat$fert_type2=="npk-22", fieldSoilDat$fert_kg2, NA)
fieldSoilDat$fert_total_22npk <- apply(fieldSoilDat[, grep("(22npk.)", names(fieldSoilDat))], 1, function(x){
  sum(as.numeric(x), na.rm=T)})
fieldSoilDat$fert_kg_2555npk1 <- ifelse(fieldSoilDat$fert_type1=="npk2555", fieldSoilDat$fert_kg1, NA)
fieldSoilDat$fert_kg_2555npk2 <- ifelse(fieldSoilDat$fert_type2=="npk2555", fieldSoilDat$fert_kg2, NA)
fieldSoilDat$fert_total_2555npk <- apply(fieldSoilDat[, grep("(2555npk.)", names(fieldSoilDat))], 1, function(x){
  sum(as.numeric(x), na.rm=T)})
#lime
fieldSoilDat$lime_outside <- ifelse(fieldSoilDat$d_lime=="lime_outside", fieldSoilDat$kg_lime, NA)
fieldSoilDat$lime_tubura <- ifelse(fieldSoilDat$d_lime=="lime_tubura", fieldSoilDat$kg_lime, NA)
fieldSoilDat$lime_both <- ifelse(fieldSoilDat$d_lime=="both_tubura_non_tubura", fieldSoilDat$kg_lime, NA)
inputVars <- names(fieldSoilDat)[grep("field_length|field_width|dim|fert_kg_|fert_total_|lime_", names(fieldSoilDat))]
fieldSoilDat[,inputVars] <-sapply(fieldSoilDat[,inputVars], as.numeric)
#urea
fieldSoilDat$fert_kgare_urea1 <- fieldSoilDat$fert_kg_urea1/fieldSoilDat$are
fieldSoilDat$fert_kgare_urea2 <- fieldSoilDat$fert_kg_urea2/fieldSoilDat$are
fieldSoilDat$fert_kgare_urea_total <- fieldSoilDat$fert_total_urea/fieldSoilDat$are
#dap
fieldSoilDat$fert_kgare_dap1 <- fieldSoilDat$fert_kg_dap1/fieldSoilDat$are
fieldSoilDat$fert_kgare_dap2 <- fieldSoilDat$fert_kg_dap2/fieldSoilDat$are
fieldSoilDat$fert_kgare_dap_total <- fieldSoilDat$fert_total_dap/fieldSoilDat$are
#npk17
fieldSoilDat$fert_kgare_17npk1 <- fieldSoilDat$fert_kg_17npk1/fieldSoilDat$are
fieldSoilDat$fert_kgare_17npk2 <- fieldSoilDat$fert_kg_17npk2/fieldSoilDat$are
fieldSoilDat$fert_kgare_17npk_total <- fieldSoilDat$fert_total_17npk/fieldSoilDat$are
#npk22
fieldSoilDat$fert_kgare_22npk1 <- fieldSoilDat$fert_kg_22npk1/fieldSoilDat$are
fieldSoilDat$fert_kgare_22npk2 <- fieldSoilDat$fert_kg_22npk2/fieldSoilDat$are
fieldSoilDat$fert_kgare_22npk_total <- fieldSoilDat$fert_total_22npk/fieldSoilDat$are
#2555 npk
fieldSoilDat$fert_kgare_2555npk1 <- fieldSoilDat$fert_kg_2555npk1/fieldSoilDat$are
fieldSoilDat$fert_kgare_2555npk2 <- fieldSoilDat$fert_kg_2555npk2/fieldSoilDat$are
fieldSoilDat$fert_kgare_2555npk_total <- fieldSoilDat$fert_total_2555npk/fieldSoilDat$are

4.12.2 Visualize field variables

fieldInputVars <- names(fieldSoilDat)[grep("field_length|field_width|dim|fert_kgare_", names(fieldSoilDat))]
for(i in 1:length(fieldInputVars)){
    base <- ggplot(fieldSoilDat, aes(x=fieldSoilDat[,fieldInputVars[i]])) + labs(x = fieldInputVars[i], title=fieldInputVars[i])
    temp1 <- base + geom_density()
    temp2 <- base + geom_histogram()
    #temp2 <- boxplot(r[,numVars[i]],main=paste0("Variable: ", numVars[i]))
    multiplot(temp1, temp2, cols = 2)
}

TODO: make certain I do some checking of these values above and if not above, here.

# fieldDat$season_16a <- ifelse(grepl("16a", fieldDat$n_tubura_season), 1, 0)
# fieldDat$season_16b <- ifelse(grepl("16b", fieldDat$n_tubura_season), 1, 0)
# fieldDat$season_17a <- ifelse(grepl("17a", fieldDat$n_tubura_season), 1, 0)
# fieldDat$notClient3Seasons <- ifelse(grepl("not_a_client", fieldDat$n_tubura_season), 1, 0)

Check field dimensions:

ggplot(fieldSoilDat, aes(x=field_width, y=field_length)) + 
  geom_point() +
  labs(title= "Field dimensions", x = "Width (m)", y= "Length (m)")

4.13 Map of samples

library(dismo)
if (!(exists("rwanda"))){
  # Only need to geocode once per session library(dismo)
  rwanda <- try(geocode("Rwanda"))
  # If the internet fails, use a local value 
  if (class(rwanda) == "try-error") {
    rwanda <- ""
    # arusha$longitude <- 36.68299
    # arusha$latitude <- -3.386925
  } 
}
[1] "try 2 ..."
[1] "try 3 ..."

See here for more on using markerClusterOptions in leaflet.

In the map below, the larger green circles are Tubura farmers and the smaller blue circles are control farmers. The number of observations will appear larger on the map because it’s plot level instead of farmer level.

e <- rs[!is.na(rs$lon),]
ss <- SpatialPointsDataFrame(coords = e[, c("lon", "lat")], data=e)
pal <- colorNumeric(c("navy", "green"), domain=unique(ss$client))
map <- leaflet() %>% addTiles() %>%
  setView(lng=rwanda$longitude, lat=rwanda$latitude, zoom=8) %>%
  addCircleMarkers(lng=ss$lon, lat=ss$lat, 
                   radius= ifelse(ss$client==1, 10,6),
                   color = pal(ss$client),
clusterOptions = markerClusterOptions(disableClusteringAtZoom=13, spiderfyOnMaxZoom=FALSE))
map

4.14 Lessons for Nathaniel

Here are the key pieces of feedback for the next survey round:

  • Variable naming convention - quite a bit of work had to be done to work with the data. Any plot specific variable should be named with _(year)(season) at the end. This will make it easy to reshape those variables into plot level variables.
  • Check variables - some of the input variables are quite large. Is it possible to have CC automatically calculate quantities in a per are rate and signal the enumerator if the values seem high? Better field estimates should help with this but that sort of check would be a good reality check in the field.
  • Soil texturing - how long did this take? I think we can have this done in the lab
  • Seed types - not many farmers responded to the seed type question. Do we have a reason why from either farmers or enumerators?
  • NAs - so many NAs in the data! Why?
  • Timing for upcoming survey
  • Commcare: Please ensure that the variable labels are in the right language box. The export I’m getting directly from Commcare is a mix of English and Kinyarwanda names. I assume that’s because the labels were not in the right boxes.

Analysis TODO: * feature creation (in process) * matching (talk to Maya) + * following previous template (look back) +

For next week: * talk with Maya about matching longitudinally * soil graphs

5 Analysis

Same as the baseline analysis but with two seasons of data

TODO: confirm that d_client is reflecting the right status as a farmer in the data. Is it baseline? Is it round 1? Is it a combo of the two?

5.1 Demographic summary

5.1.1 Identifier variables

Create a record of how many farmers are joining and leaving Tubura between the baseline and the first follow up round.

Using fieldDat to have 16a counts

#table(fieldSoilDat$d_client, fieldSoilDat$season)
fieldDat %>% 
  dplyr::select(sample_id, season, d_client) %>%
  group_by(sample_id) %>%
  spread(., season, d_client) %>%
  rename(
    client15b = `15b`,
    client16a = `16a`,
    client16b = `16b`
  ) %>%
  mutate(
    becameClient = ifelse(client15b==0 & client16b==1, 1, 0),
    becameControl = ifelse(client15b==1 & client16b==0, 1, 0),
    stayedClient = ifelse(client15b==1 & client16b==1, 1, 0),
    stayedControl = ifelse(client15b==0 & client16b==0, 1, 0)
  ) %>% 
  ungroup() %>%
  dplyr::summarize_each(
    funs(mean= mean(., na.rm=T)), -c(sample_id, client15b, client16a, client16b)
  ) %>% 
  mutate_each(
    funs(paste0(round(.,2)*100, "%"))
  ) %>%
  kable(caption="Movement in Sample", format='markdown')
becameClient_mean becameControl_mean stayedClient_mean stayedControl_mean
3% 15% 33% 46%

5.1.2 Client count

Using fieldDat to have 16a counts

clientCount <- fieldDat %>% 
  dplyr::select(sample_id, season, d_client) %>%
  group_by(sample_id) %>%
  spread(., season, d_client) %>%
  rename(
    client15b = `15b`,
    client16a = `16a`,
    client16b = `16b`
  )
clientCountTab <- cbind(
  as.data.frame(table(clientCount$client15b)),
  as.data.frame(table(clientCount$client16b)))
clientCountTab <- clientCountTab[,-3]
names(clientCountTab) <- c("Treatment", "Clients 15b", "Clients 16b")
write.csv(clientCountTab, file=paste0("output/", "clientCountTab.csv"), row.names = F)

Subset of farmers that kept status for soil regression table. TODO - decide if the analyses that follow need to be turned into functions or if it’s sufficient to set the sample here and use that same sample going forward.

sameStatusVec <- soilDat %>%
  dplyr::select(sample_id, season, d_client) %>%
  group_by(sample_id) %>%
  spread(., season, d_client) %>%
  as.data.frame() %>%
  mutate(
    same = ifelse(`15b`==`16b`, 1, 0)
  ) %>%
  filter(same==1)
sameStatus <- soilDat[soilDat$sample_id %in% sameStatusVec$sample_id,]
sameStatusCount <- table(sameStatus$d_client)/2
write.csv(sameStatusCount, file="output/sameStatusCount.csv")
#sameStatusfs <- soilDat[soilDat$sample_id %in% sameStatusVec$sample_id,] #

5.2 Soil summary

5.2.1 Initial soil graphs

These graphs are a peek at how soil parameter averages and differences look between treatment and control farmers using both baseline and round 1 values. This is a preliminary rough look. Next steps include:

  • Confirming client assignment and clarifying status
  • Additional cleaning of soil variables
  • reconcile using IQR or SD method for adjusting data
  • Matching of clients to derive a more causal look at client effects on soil parameters.

Helpful code for putting the graphics together

5.2.2 Soil means and diffs

TODO: Clean soil data here once Step and Patrick have some feedback regarding what are reasonable and unreasonable values.

soilOut has common modifications. All resulting soil outcomes are made using that. Soil outcomes are named soilOut.outcome_name. This uses only farmers that have the same treatment status in 15b and 16b

soilOut <- soilDat %>% 
  filter(soilDat$sample_id %in% sameStatusVec$sample_id) %>%
  mutate(
  measure = ifelse(season=="15b", 1, 
                   ifelse(season=="16b", 2,NA))
) %>% arrange(measure) %>%
  as.data.frame()
soilOut.Mean <- soilOut %>%
  group_by(sample_id) %>%
  summarize_each(
    funs(mean(., na.rm=T)), -c(SSN, season, measure, d_client)
  ) %>% 
  ungroup() %>% 
  as.data.frame() %>%
  rename_(.dots = setNames(names(.), gsub("X\\.|\\.", "", names(.))))
# find a way to fit this into piping
names(soilOut.Mean)[2:19] <- paste0(names(soilOut.Mean)[2:19], ".mean")
# 0s are when we have only one observation
soilOut.Diff <- soilOut %>%
  group_by(sample_id) %>%
  # summarise_each(
  #   funs(if_else(length(.)==2, diff(x), .)), -c(SSN, season, sample_id, measure)
  # ) %>% ungroup() %>% as.data.frame()
  mutate_each(
    funs(. - lag(., default=first(.))), -c(SSN, season, measure, d_client)
  ) %>%
  filter(measure==2) %>%
  as.data.frame() %>%
  rename_(.dots = setNames(names(.), gsub("X\\.|\\.", "", names(.))))
# find a way to fit this into piping
names(soilOut.Diff)[1:18] <- paste0(names(soilOut.Diff)[1:18], ".diff")
# gather soil outcomes to merge back together
#soilTrans <- list(ls()[grep("soilOut.", ls())])
soilMerge <- merge(soilOut.Mean, soilOut.Diff,by="sample_id")
library(tidyr)
library(RGraphics)
soilGraph <- soilMerge %>%
  gather(variable, value, -c(SSN, sample_id, measure, season, d_client)) %>%
  separate(variable, c("soilChar", "type"), sep="\\.")
for(i in 1:length(unique(soilGraph$soilChar))){
  for(j in 1:length(unique(soilGraph$type))){
    
    temp <- soilGraph %>% 
      filter(soilChar==unique(soilGraph$soilChar)[i] & soilGraph$type==unique(soilGraph$type)[j]) %>%
      mutate(
        value = ifelse(is.infinite(value), NA, value)
      )
    
    
     gph = ggplot(temp, aes(x = d_client, y=value)) + 
       geom_boxplot() + 
       labs(title = paste("NON-MATCHED PRELIM -", unique(soilGraph$soilChar)[i], unique(soilGraph$type)[j], sep=" "), x = "Treatment v. Control", y=unique(soilGraph$soilChar)[i])
    
    
    
      tab = tableGrob(
        aggregate(temp$value, by=list(temp$d_client), function(x){
        paste(round(mean(x, na.rm=T),2), " (", round(sd(x,na.rm=T),2), ")", sep="")
          }),
        cols = c("Treatment", "Mean (sd)"))
      
      grid.arrange(gph, tab, ncol=2, top=paste("NON-MATCHED PRELIM -", unique(temp$soilChar), unique(temp$type), sep=" "))
  }
}

5.2.3 Soil summary table

Note: This table is preliminary and does not reflect values ready for interpretation (6/19). This uses all farmers.

tabOut <- do.call(rbind, lapply(split(soilGraph, list(soilGraph$type, soilGraph$soilChar)), function(x){
  
  x <- x %>% mutate(
   value = ifelse(is.infinite(value), NA, value) 
  )
  
  temp = aggregate(x$value, by=list(x$d_client), FUN=mean, na.rm=T)
  pval = round(wilcox.test(value ~ d_client, data=x)$p.value,3)
  Tmean = round(temp$x[2], 2)
  Cmean = round(temp$x[1], 2)
  
  output = data.frame(cat = paste0(unique(x$soilChar), " - ", unique(x$type)), Cmean, Tmean, pval)
  return(output)
  
}))
tabOut <- tabOut %>% 
  mutate(pval.adj = round(p.adjust(pval, "fdr"),3)) %>%
  arrange(pval.adj)
kable(tabOut, format='markdown', row.names = F, col.names = c("Outcome", "Control mean", "OAF mean", "p-value", "adj. p-value"))
Outcome Control mean OAF mean p-value adj. p-value
Boron - diff -0.19 -0.19 0.182 0.955
Calcium - mean 826.27 801.85 0.396 0.955
Copper - mean 2.38 2.35 0.359 0.955
ECSalts - diff -47.10 -46.65 0.354 0.955
ECSalts - mean 80.68 81.02 0.352 0.955
ExchangeableAcidity - diff -0.26 -0.25 0.296 0.955
Iron - mean 174.56 179.38 0.137 0.955
Magnesium - diff -20.14 -26.30 0.321 0.955
Manganese - mean 80.25 78.37 0.393 0.955
pH - diff 0.01 -0.01 0.285 0.955
pH - mean 5.51 5.49 0.398 0.955
Phosphorus - mean 16.18 16.41 0.293 0.955
TotalNitrogen - mean 0.15 0.15 0.255 0.955
Zinc - diff -0.21 -0.18 0.308 0.955
Zinc - mean 2.37 2.34 0.263 0.955
Boron - mean 0.39 0.38 0.876 0.963
Calcium - diff -31.72 -39.04 0.627 0.963
CEC - diff 0.04 0.05 0.913 0.963
CEC - mean 9.37 9.24 0.576 0.963
Copper - diff -0.24 -0.25 0.534 0.963
ExchangeableAcidity - mean 0.65 0.66 0.573 0.963
ExchangeableAluminium - diff -0.25 -0.25 0.515 0.963
ExchangeableAluminium - mean 0.46 0.46 0.605 0.963
Iron - diff -8.40 -7.85 0.709 0.963
Magnesium - mean 200.48 200.36 0.828 0.963
Manganese - diff -26.14 -27.56 0.642 0.963
OrganicCarbon - diff 0.13 0.14 0.931 0.963
OrganicCarbon - mean 2.15 2.14 0.805 0.963
Phosphorus - diff -0.67 -0.62 0.893 0.963
PhosphorusSorptionIndexPSI - mean 68.09 68.16 0.679 0.963
Potassium - diff 35.16 34.56 0.842 0.963
Potassium - mean 140.19 139.85 0.936 0.963
Sulphur - diff -0.77 -0.75 0.803 0.963
Sulphur - mean 17.61 17.78 0.558 0.963
TotalNitrogen - diff -0.01 -0.01 0.915 0.963
PhosphorusSorptionIndexPSI - diff 104.57 103.80 0.987 0.987

5.2.4 Longitudinal soil graphs

soilLineGraph <- soilOut %>%
  group_by(d_client, season) %>%
  summarize_each(
    funs(mean(., na.rm=T)), -c(SSN, sample_id)
  ) %>%
  gather(variable, value, -c(season, d_client)) %>%
  filter(variable %in% keySoilVars)
  
pdf(file=paste("output/", "key soil vars - longitudinal.pdf", sep = ""), width=11, height=8.5)
for(i in 1:length(keySoilVars)){
    print(ggplot(subset(soilLineGraph, soilLineGraph$variable==keySoilVars[i]), aes(x = season, y = value, group=d_client, color=d_client)) + 
      geom_line() +
      labs(title=paste(keySoilVars[i], "over time by client status - same only", sep= " "),
          x= "Season", y=keySoilVars[i], color="Treatment")
    )
  makeFootnote(footnote)
    
}
dev.off()
null device 
          1 

Here is the table in section 1 of the report.

soilLineGraph %>%
  spread(season, value) %>%
  arrange(variable) %>%
  rename(
    year1 = `15b`,
    year2 = `16b`
  ) %>%
  mutate_if(
    is.numeric, funs(round(.,3))
  ) %>% 
  write.csv(., file="output/sumTab1.csv")

5.2.5 Regressions

See sketch of SHS report. Remember that sameStatus are the farmers that kept their status between baseline and endline. The two models of interest are:

  • Individual fixed effects account for things specicic to farmer that don’t change over time
  • can control for unobserved sources of heterogeneity over time, very sensitive to model
  • add in other data points that do change over time
  • so add in things that change over time that plausibly affect our outcome
  • fertilizer and seed use are synoymous with being a client or not, highly endogenous
  • run two regs
  • one with oaf
  • one with oaf and fertilizer
  • things like slope are collinear
  • individual fixed effects makes more sense than using PSM now that we have multiple years.
  • means by directional changes
  • papers using fixed effects by miguel on whether changes to rural to urban areas and income

Consider including:

  • time FEs
  • age and a squared age term
  • gender (absorbed by fixed effects)
  • years of education (absorbed by fixed effects)
  • bootstrapped st. errors / robust standard errors

Helpful link for executing code in parallel

source("../oaflib/plm.R")
fieldSoilDat <- fieldSoilDat %>%
  mutate(
    age2 = age^2
  )
indFeList <- list("as.factor(d_client)", 
                  c("as.factor(d_client)", "as.factor(sample_id)"),
                  c("as.factor(d_client)", "as.factor(sample_id)", "as.factor(season)"),
                  c("as.factor(d_client)", "as.factor(sample_id)", "as.factor(season)", "age", "age2"))
forceUpdate <- FALSE
# run this in parallel to speed up the process
# load the data and variables and packages into the cluster
regFile <- "regFile.RData"
#forceUpdate <- forceUpdateAll
if(!file.exists(regFile) || forceUpdate) {
library(parallel)
no_cores <- detectCores() - 1
cl <- makeCluster(no_cores, type="FORK")
clusterEvalQ(cl, "plm")
clusterExport(cl, "fieldSoilDat")
clusterExport(cl, "keySoilVars")
clusterExport(cl, "indFeList")
indFeLoop <- parLapply(cl, indFeList, function(mod){
  lapply(keySoilVars, function(outcome){
    form = lm(reformulate(termlabels = mod, response = outcome), data=fieldSoilDat)
    
    pdf(file=paste("output/", paste0(outcome, paste(mod, collapse = "")), ".pdf", sep = "")) 
    print(plot(form))
    dev.off()
    
    form = plm(form, c("sample_id", "age", "age2"))
    
    rownames(form) = paste(rownames(form), outcome, sep = " ")
    return(form)
  })
  
})
stopCluster(cl)
save(indFeLoop, file=regFile)
} else {
  load("regFile.RData")
}

Notes:

Based on regression diagnostics for each outcome, here are the steps I’m taking:

  • Calcium - check the heavy tails, make model robust?
  • Magnesium - same
  • pH - same, not too bad but some concerning values
  • Carbon - actually not too bad but check heavy tails
  • Nitrogen - weird. Check for heavy tails

Links for robust regression:

Check out robustbase lmrob for robust lm and rlm from MASS. Only use the full model specification.

forceUpdate <- FALSE
# run this in parallel to speed up the process
# load the data and variables and packages into the cluster
regRobustFile <- "regRobustFile.RData"
#forceUpdate <- forceUpdateAll
if(!file.exists(regRobustFile) || forceUpdate) {
library(parallel)
no_cores <- detectCores() - 1

cl <- makeCluster(no_cores, type="FORK")
clusterEvalQ(cl, "plm")
clusterExport(cl, "fieldSoilDat")
clusterExport(cl, "keySoilVars")
clusterExport(cl, "indFeList")

indFeLoop <- parLapply(cl, keySoilVars, function(outcome){
    
  #test  = lmrob(reformulate(termlabels = indFeList[[4]], response = outcome), data=fieldSoilDat)
  
    # address duplicate pairs of X and Y >> but what is our X when we have all these features?
    form = rlm(reformulate(termlabels = indFeList[[4]], response = outcome), data=fieldSoilDat)
    
    pdf(file=paste("output/robust/", paste0(outcome, paste(indFeList[[4]], collapse = "")), ".pdf", sep = "")) 
    print(plot(form))
    dev.off()
    
    sumTab <- summary(form)
    
    
    #form = plm(form, c("sample_id", "age", "age2"))
    
    #rownames(form) = paste(rownames(form), outcome, sep = " ")
    return(form)
})
  
stopCluster(cl)
save(indFeLoop, file=regRobustFile)
} else {
  load("regRobustFile.RData")
}

And combine model outputs into tables for each model

modExport <- lapply(indFeLoop, function(models){
  do.call(rbind, models)
})
for(i in 1:length(modExport)){
  write.csv(modExport[i], file=paste0("output/","regOutput_", i, ".csv"), row.names = T)
}
modExport <- lapply(indFeLoop, function(models){
  do.call(rbind, models)
})

In the individual fixed effect model above, the naive model would only include a client indicator and individual fixed effects. If we add season, we lose significance on almost everything. I’d guess that as we add more likely controls we additionally lose signficance. I’ve included age and age squared along the lines of Hicks et.al.

finalModel <- modExport[4]
kable(finalModel, format="markdown")

Coefficient 95% Confidence Interval P-Value
(Intercept) pH 5.5000 5.1 to 5.9 <0.001 ***
as.factor(d_client)1 pH -0.0210 -0.055 to 0.013 0.23
as.factor(season)16b pH 0.0031 -0.012 to 0.018 0.68
(Intercept) X.Organic.Carbon 1.7000 1.3 to 2.1 <0.001 ***
as.factor(d_client)1 X.Organic.Carbon 0.0031 -0.031 to 0.038 0.86
as.factor(season)16b X.Organic.Carbon 0.1300 0.12 to 0.15 <0.001 ***
(Intercept) X.Total.Nitrogen 0.1300 0.1 to 0.15 <0.001 ***
as.factor(d_client)1 X.Total.Nitrogen 0.0020 -0.00018 to 0.0043 0.072 .
as.factor(season)16b X.Total.Nitrogen -0.0067 -0.0077 to -0.0058 <0.001 ***
(Intercept) Calcium 830.0000 450 to 1200 <0.001 ***
as.factor(d_client)1 Calcium -10.0000 -44 to 23 0.54
as.factor(season)16b Calcium -35.0000 -50 to -20 <0.001 ***
(Intercept) Magnesium 170.0000 77 to 260 <0.001 ***
as.factor(d_client)1 Magnesium -0.6500 -8.8 to 7.5 0.88
as.factor(season)16b Magnesium -23.0000 -27 to -20 <0.001 ***

write.csv(finalModel, file="output/indFe.csv")

Save data for cleaning

save(fieldDat, file="fieldDat_final.Rdata")
save(fieldSoilDat, file="fieldSoilDat_final.Rdata")

6 Appendix

What happens if we re-run out model but with 25% fewer observations. I guess what we’re concerned with here is power and the confidence intervals around our estimates. Set this up and check it out.

fieldSoilDat$rand <- rnorm(length(fieldSoilDat), mean=0, sd=1)
Error in `$<-.data.frame`(`*tmp*`, "rand", value = c(2.03079094492891,  : 
  replacement has 100 rows, data has 4819
# power
#ci
indFeList <- list("as.factor(d_client)", 
                  c("as.factor(d_client)", "as.factor(sample_id)"),
                  c("as.factor(d_client)", "as.factor(sample_id)", "as.factor(season)"),
                  c("as.factor(d_client)", "as.factor(sample_id)", "as.factor(season)", "age", "age2"))
forceUpdate <- TRUE
# run this in parallel to speed up the process
# load the data and variables and packages into the cluster
regFile <- "regFile_sub.RData"
#forceUpdate <- forceUpdateAll
if(!file.exists(regFile) || forceUpdate) {
library(parallel)
no_cores <- detectCores() - 1
cl <- makeCluster(no_cores, type="FORK")
clusterEvalQ(cl, "plm")
clusterExport(cl, "fieldSoilDat")
clusterExport(cl, "keySoilVars")
clusterExport(cl, "indFeList")
indFeLoop <- parLapply(cl, indFeList, function(mod){
  lapply(keySoilVars, function(outcome){
    form = lm(reformulate(termlabels = mod, response = outcome), data=sbset)
    
    pdf(file=paste("output/", paste0(outcome, paste(mod, collapse = "")), ".pdf", sep = "")) 
    print(plot(form))
    dev.off()
    
    form = plm(form, c("sample_id", "age", "age2"))
    
    rownames(form) = paste(rownames(form), outcome, sep = " ")
    return(form)
  })
  
})
stopCluster(cl)
save(indFeLoop, file=regFile)
} else {
  load("regFile_sub.RData")
}
not plotting observations with leverage one:
  3, 4, 23, 37, 43, 62, 67, 68, 90, 93, 94, 98, 99, 108, 119, 123, 125, 127, 137, 143, 156, 173, 184, 189, 190, 200, 213, 214, 225, 233, 235, 244, 245, 248, 250, 252, 266, 267, 270, 287, 291, 298, 303, 319, 323, 335, 341, 346, 373, 390, 392, 395, 404, 405, 410, 414, 416, 432, 440, 441, 451, 453, 455, 481, 493, 495, 502, 514, 526, 530, 545, 546, 549, 550, 553, 564, 590, 602, 607, 611, 617, 625, 630, 640, 641, 649, 650, 653, 658, 667, 669, 673, 690, 691, 697, 716, 734, 754, 771, 780, 781, 784, 802, 804, 813, 821, 828, 841, 846, 859, 860, 869, 873, 901, 908, 918, 920, 923, 977, 978, 988, 989, 994, 999, 1003, 1007, 1010, 1012, 1015, 1016, 1022, 1023, 1038, 1044, 1046, 1052, 1055, 1067, 1069, 1071, 1072, 1076, 1081, 1087, 1093, 1098, 1103, 1106, 1120, 1127, 1134, 1136, 1159, 1163, 1164, 1166, 1168, 1179, 1184, 1192, 1193, 1199, 1205, 1211, 1214, 1220, 1226, 1228, 1230, 1231, 1232, 1235, 1248, 1254, 1258, 1259, 1263, 1264, 1297, 1298, 1300, 1310, 1313, 1329, 1330, 1335, 1340, 1352, 1353, 1355, 1374, 1375, 1389, 1398, 1399, 1411, 1413, 1421, 1426, 1446, 1479, 1486, 1489, 1491, 1494, 1495, 1498, 1509, 1514, 1518, 1532, 1533, 1535, 1538, 1540, 1541, 1543, 1546, 1553, 1579, 1583, 1585, 1601, 1609, 1627, 1629, 1636, 1637, 1645, 1654, 1659, 1674, 1676, 1688, 1708, 1715, 1725, 1736, 1763, 1770, 1775, 1779, 1782, 1783, 1785, 1787, 1799, 1803, 1809, 1813, 1815, 1817, 1826, 1828, 1835, 1841, 1848, 1858, 1865, 1871, 1873, 1898, 1901, 1905, 1908, 1912, 1931, 1937, 1947, 1952, 1959, 1960, 1971, 1978, 1992, 1993, 1998, 2004, 2014, 2015, 2020, 2026, 2036, 2041, 2046, 2047, 2070, 2072, 2077, 2082, 2084, 2091, 2095, 2098, 2124, 2125, 2126, 2136, 2155, 2166, 2171, 2175, 2176, 2177, 2189, 2194, 2203, 2212, 2220, 2221, 2223, 2229, 2234, 2239, 2243, 2251, 2259, 2267, 2280, 2282, 2284, 2307, 2310, 2311, 2320, 2326, 2328, 2331, 2332, 2344, 2354, 2367, 2371, 2376, 2389, 2410, 2413, 2414, 2430, 2445, 2450, 2453, 2461, 2463, 2464, 2465, 2483, 2497, 2504, 2507, 2510, 2513, 2523, 2536, 2540, 2548, 2552, 2556, 2557, 2568, 2571, 2575, 2580, 2605, 2619, 2622, 2624, 2629, 2641, 2645, 2647, 2652, 2657, 2665, 2668, 2680, 2682, 2684, 2687, 2690, 2691, 2693, 2698, 2715, 2719, 2727, 2728, 2731, 2759, 2765, 2775, 2777, 2778, 2782, 2789, 2797, 2804, 2813, 2820, 2836, 2841, 2846, 2848, 2854, 2855, 2858, 2866, 2870, 2872, 2876, 2892, 2894, 2899, 2909, 2912, 2914, 2916, 2928, 2931, 2933, 2939, 2940, 2941, 2942, 2949, 2962, 2971, 2984, 2985, 2987, 2996, 2999, 3001, 3002, 3027, 3034, 3065, 3071, 3082, 3084, 3085, 3093, 3097, 3098, 3106, 3109, 3114, 3123, 3124, 3136, 3144, 3152, 3160, 3165, 3166, 3172, 3173, 3179, 3186, 3189, 3200, 3204, 3209, 3217, 3223, 3224, 3227, 3231, 3243, 3282, 3286, 3287, 3293, 3303, 3307, 3308, 3315, 3323, 3324, 3331, 3353, 3363, 3370, 3374, 3379, 3381, 3382, 3384, 3388, 3389, 3393, 3401, 3402, 3410, 3411, 3415, 3423, 3432, 3439, 3444, 3451, 3454, 3460, 3463, 3465, 3472, 3476, 3482, 3489, 3490, 3497, 3499, 3500, 3504, 3508, 3511, 3513, 3516, 3517, 3524, 3529, 3535, 3538, 3545, 3549, 3556, 3557, 3560, 3561, 3562, 3564, 3567, 3569, 3589not plotting observations with leverage one:
  3, 4, 23, 37, 43, 62, 67, 68, 90, 93, 94, 98, 99, 108, 119, 123, 125, 127, 137, 143, 156, 173, 184, 189, 190, 200, 213, 214, 225, 233, 235, 244, 245, 248, 250, 252, 266, 267, 270, 287, 291, 298, 303, 319, 323, 335, 341, 346, 373, 390, 392, 395, 404, 405, 410, 414, 416, 432, 440, 441, 451, 453, 455, 481, 493, 495, 502, 514, 526, 530, 545, 546, 549, 550, 553, 564, 590, 602, 607, 611, 617, 625, 630, 640, 641, 649, 650, 653, 658, 667, 669, 673, 690, 691, 697, 716, 734, 754, 771, 780, 781, 784, 802, 804, 813, 821, 828, 841, 846, 859, 860, 869, 873, 901, 908, 918, 920, 923, 977, 978, 988, 989, 994, 999, 1003, 1007, 1010, 1012, 1015, 1016, 1022, 1023, 1038, 1044, 1046, 1052, 1055, 1067, 1069, 1071, 1072, 1076, 1081, 1087, 1093, 1098, 1103, 1106, 1120, 1127, 1134, 1136, 1159, 1163, 1164, 1166, 1168, 1179, 1184, 1192, 1193, 1199, 1205, 1211, 1214, 1220, 1226, 1228, 1230, 1231, 1232, 1235, 1248, 1254, 1258, 1259, 1263, 1264, 1297, 1298, 1300, 1310, 1313, 1329, 1330, 1335, 1340, 1352, 1353, 1355, 1374, 1375, 1389, 1398, 1399, 1411, 1413, 1421, 1426, 1446, 1479, 1486, 1489, 1491, 1494, 1495, 1498, 1509, 1514, 1518, 1532, 1533, 1535, 1538, 1540, 1541, 1543, 1546, 1553, 1579, 1583, 1585, 1601, 1609, 1627, 1629, 1636, 1637, 1645, 1654, 1659, 1674, 1676, 1688, 1708, 1715, 1725, 1736, 1763, 1770, 1775, 1779, 1782, 1783, 1785, 1787, 1799, 1803, 1809, 1813, 1815, 1817, 1826, 1828, 1835, 1841, 1848, 1858, 1865, 1871, 1873, 1898, 1901, 1905, 1908, 1912, 1931, 1937, 1947, 1952, 1959, 1960, 1971, 1978, 1992, 1993, 1998, 2004, 2014, 2015, 2020, 2026, 2036, 2041, 2046, 2047, 2070, 2072, 2077, 2082, 2084, 2091, 2095, 2098, 2124, 2125, 2126, 2136, 2155, 2166, 2171, 2175, 2176, 2177, 2189, 2194, 2203, 2212, 2220, 2221, 2223, 2229, 2234, 2239, 2243, 2251, 2259, 2267, 2280, 2282, 2284, 2307, 2310, 2311, 2320, 2326, 2328, 2331, 2332, 2344, 2354, 2367, 2371, 2376, 2389, 2410, 2413, 2414, 2430, 2445, 2450, 2453, 2461, 2463, 2464, 2465, 2483, 2497, 2504, 2507, 2510, 2513, 2523, 2536, 2540, 2548, 2552, 2556, 2557, 2568, 2571, 2575, 2580, 2605, 2619, 2622, 2624, 2629, 2641, 2645, 2647, 2652, 2657, 2665, 2668, 2680, 2682, 2684, 2687, 2690, 2691, 2693, 2698, 2715, 2719, 2727, 2728, 2731, 2759, 2765, 2775, 2777, 2778, 2782, 2789, 2797, 2804, 2813, 2820, 2836, 2841, 2846, 2848, 2854, 2855, 2858, 2866, 2870, 2872, 2876, 2892, 2894, 2899, 2909, 2912, 2914, 2916, 2928, 2931, 2933, 2939, 2940, 2941, 2942, 2949, 2962, 2971, 2984, 2985, 2987, 2996, 2999, 3001, 3002, 3027, 3034, 3065, 3071, 3082, 3084, 3085, 3093, 3097, 3098, 3106, 3109, 3114, 3123, 3124, 3136, 3144, 3152, 3160, 3165, 3166, 3172, 3173, 3179, 3186, 3189, 3200, 3204, 3209, 3217, 3223, 3224, 3227, 3231, 3243, 3282, 3286, 3287, 3293, 3303, 3307, 3308, 3315, 3323, 3324, 3331, 3353, 3363, 3370, 3374, 3379, 3381, 3382, 3384, 3388, 3389, 3393, 3401, 3402, 3410, 3411, 3415, 3423, 3432, 3439, 3444, 3451, 3454, 3460, 3463, 3465, 3472, 3476, 3482, 3489, 3490, 3497, 3499, 3500, 3504, 3508, 3511, 3513, 3516, 3517, 3524, 3529, 3535, 3538, 3545, 3549, 3556, 3557, 3560, 3561, 3562, 3564, 3567, 3569, 3589
modExport <- lapply(indFeLoop, function(models){
  do.call(rbind, models)
})
for(i in 1:length(modExport)){
  write.csv(modExport[i], file=paste0("output/","regOutputSub_", i, ".csv"), row.names = T)
}
LS0tCnRpdGxlOiAiUndhbmRhIFNvaWwgSGVhbHRoIFN0dWR5IC0gUm91bmQgMSIKYXV0aG9yOiAnW01hdHQgTG93ZXNdKG1haWx0bzptYXR0Lmxvd2VzQG9uZWFjcmVmdW5kLm9yZyknCmRhdGU6ICdgciBmb3JtYXQoU3lzLnRpbWUoKSwgIiVCICVkLCAlWSIpYCcKb3V0cHV0OgogIGh0bWxfbm90ZWJvb2s6CiAgICBudW1iZXJfc2VjdGlvbnM6IHllcwogICAgY29kZV9mb2xkaW5nOiBzaG93CiAgICB0aGVtZTogZmxhdGx5CiAgICB0b2M6IHllcwogICAgdG9jX2RlcHRoOiA2CiAgICB0b2NfZmxvYXQ6IHllcwotLS0KCmBgYHtyIHNldHVwLCBpbmNsdWRlPUZBTFNFfQojIyMjIHNldCB1cAojIyBjbGVhciBlbnZpcm9ubWVudCBhbmQgY29uc29sZQpybShsaXN0ID0gbHMoKSkKY2F0KCJcMDE0IikKCiMjIHNldCB1cCBzb21lIGdsb2JhbCBvcHRpb25zCiMgYWx3YXlzIHNldCBzdHJpbmdzQXNGYWN0b3JzID0gRiB3aGVuIGxvYWRpbmcgZGF0YQpvcHRpb25zKHN0cmluZ3NBc0ZhY3RvcnM9RkFMU0UpCgojIHNob3cgdGhlIGNvZGUKa25pdHI6Om9wdHNfY2h1bmskc2V0KGVjaG8gPSBUUlVFKQoKIyBkZWZpbmUgYWxsIGtuaXRyIHRhYmxlcyB0byBiZSBodG1sIGZvcm1hdApvcHRpb25zKGtuaXRyLnRhYmxlLmZvcm1hdCA9ICdodG1sJykKCiMgY2hhbmdlIGNvZGUgY2h1bmsgZGVmYXVsdCB0byBub3Qgc2hvdyB3YXJuaW5ncyBvciBtZXNzYWdlcwprbml0cjo6b3B0c19jaHVuayRzZXQod2FybmluZyA9IEZBTFNFLCBtZXNzYWdlID0gRkFMU0UpCgpsaWJzIDwtIGMoImRwbHlyIiwgInJlc2hhcGUyIiwgImtuaXRyIiwgImdncGxvdDIiLCAidGliYmxlIiwgInJlYWR4bCIsIAogICAgIk1BU1MiLCAiZ3JpZEV4dHJhIiwgImNvd3Bsb3QiLCAicm9idXN0YmFzZSIsICJjYXIiLCAiUlN0YXRhIiwgImZvcmVpZ24iLAogICAgInRpZHlyIiwgInJlYWR4bCIpCmxhcHBseShsaWJzLCByZXF1aXJlLCBjaGFyYWN0ZXIub25seSA9IFQsIHF1aWV0bHkgPSBULCB3YXJuLmNvbmZsaWN0cyA9IEYpCgojIyMjIGRlZmluZSBoZWxwZnVsIGZ1bmN0aW9ucwojIGRlZmluZSBmdW5jdGlvbiB0byBhZGp1c3QgdGFibGUgd2lkdGhzCmh0bWxfdGFibGVfd2lkdGggPC0gZnVuY3Rpb24oa2FibGVfb3V0cHV0LCB3aWR0aCkgewogIHdpZHRoX2h0bWwgPC0gcGFzdGUwKHBhc3RlMCgnPGNvbCB3aWR0aD0iJywgd2lkdGgsICciPicpLCBjb2xsYXBzZSA9ICJcbiIpCiAgc3ViKCI8dGFibGU+IiwgcGFzdGUwKCI8dGFibGU+XG4iLCB3aWR0aF9odG1sKSwga2FibGVfb3V0cHV0KQp9CgpvcHRpb25zKCJSU3RhdGEuU3RhdGFWZXJzaW9uIiA9IDEyKQpvcHRpb25zKCJSU3RhdGEuU3RhdGFQYXRoIiA9ICIvQXBwbGljYXRpb25zL1N0YXRhL1N0YXRhU0UuYXBwL0NvbnRlbnRzL01hY09TL3N0YXRhLXNlIikKYGBgCgojIE9iamVjdGl2ZXMKClRoZSBvYmplY3RpdmVzIG9mIHRoaXMgbm90ZWJvb2sgYXJlIHRvIGFuYWx5emUgdGhlIHJlc3VsdHMgZnJvbSB0aGUgZmlyc3QgZm9sbG93IHVwIHJvdW5kIG9mIHRoZSBSd2FuZGEgbG9uZyB0ZXJtIHNvaWwgaGVhbHRoIHN0dWR5LgoKIyBLZXkgVGFrZWF3YXlzCgo+IFNlZSBzZWN0aW9uIHdpdGggW05vdGVzIGZvciBOYXRoYW5pZWxdKCNsZXNzb25zLWZvci1uYXRoYW5pZWwpCgo+IFNlZSBzZWN0aW9uIHdpdGggW05vdGVzIGZvciBQYXRyaWNrIGFuZCBTdGVwXSgjc29pbC1ub3Rlcy1mb3ItcGF0cmljay1hbmQtc3RlcCkKCj4gW1BhaXJlZCBZaWVsZCBhbmQgU29pbF0oI2NsZWFuLXNvaWwtaWRzKSBpZHMgYXJlIGEgbWVzcy4gV2UgbG9zZSBhIGxvdCBvZiBvYnNlcnZhdGlvbnMgZHVlIHRvIHVucmVjb25jaWxpYWJsZSBkdXBsaWNhdGVzIG9yIGlkcyB0aGF0IHNpbXBseSBkb24ndCBoYXZlIGEgbWF0Y2guIFdlIGxvc2UgYWxtb3N0IDUwMCBvYnNlcnZhdGlvbnMuCgo+IFNlZSBbaW5pdGlhbCB5aWVsZCByZXNwb25zZSBhbmFseXNpc10oI2luZGl2aWR1YWwtc29pbC1tb2RlbHMpCgpUT0RPIC0gY2hlY2sgcHJvamVjdGlvbiBmcm9tIGJhc2VsaW5lIG1hcHMsIGFyZSB0aGV5IHNoaWZ0ZWQgb3Zlcj8KVE9ETyAtIGhvdyB0byBjb25uZWN0IHBob3RvcyB0byBmYXJtZXJzIGZvciBlbnVtZXJhdG9ycwoKIyBEYXRhIFByZXAKCkknbSBnb2luZyB0byBsb2FkIHRoZSBiYXNlbGluZSBkYXRhIGZyb20gdGhlIGJhc2VsaW5lIGFuYWx5c2lzLiBUaGUgcmVwb3J0IGFuZCBkYXRhIGNhbiBiZSBmb3VuZCBoZXJlLiBJJ2xsIGxvYWQgdGhlIG5ldyBkYXRhIGRpcmVjdGx5IGZyb20gQ29tbUNhcmUuIFRoZSBvcmlnaW5hbCBiYXNlbGluZSBkYXRhIG9iamVjdCB3YXMgYGRgIGJ1dCBJJ20gZ29pbmcgdG8gbWFrZSBpdCBgYmAuIEVhY2ggc3Vic2VxdWVudCByb3VuZCB3aWxsIGJlIGByMWAsIGByMmAgYW5kIHNvIG9uLgoKT3ZlcmFsbCBJIHdhbnQgdG8gYnJpbmcgaW4gMyBkYXRhIHNvdXJjZXM6CgoqIEJhc2xpbmUgc3VydmV5IGRhdGEgYW5kIHNvaWwgZGF0YQoqIFJvdW5kIDEgc3VydmV5IGFuZCBhbmQgc29pbCBkYXRhIGZyb20gMTZCCiogUm91bmQgMSB5aWVsZCBhbmQgc29pbCBkYXRhIC0gdGhlc2UgZGF0YSBjb21lIGZyb20gcGFpcmVkIGNsaW1iaW5nIGJlYW4gaGFydmVzdCBtZWFzdXJlbWVudHMgYW5kIHNvaWwgc2FtcGxlcyBmcm9tIDE2QgoqIFdlIGNhbiBhbHNvIGxvb2sgYXQgbWFpemUgcGFpcmVkIHlpZWxkIGFuZCBzb2lsIHNhbXBsZXMgZnJvbSAxN0EuCgojIyBCYXNlbGluZSBkYXRhCgpgYGB7cn0KZGF0YURpciA8LSBub3JtYWxpemVQYXRoKGZpbGUucGF0aCgiLi4iLCAiLi4iLCAiZGF0YSIpKQpmb3JjZVVwZGF0ZUFsbCA8LSBGQUxTRQpgYGAKCmBgYHtyfQpiYXNlbGluZURpciA8LSBub3JtYWxpemVQYXRoKGZpbGUucGF0aCgiLi4iLCAicndfYmFzZWxpbmUiLCAiZGF0YSIpKQoKbG9hZChmaWxlPXBhc3RlMChiYXNlbGluZURpciwgIi9zaHMgcncgYmFzZWxpbmUgZnVsbCBzb2lsLlJkYXRhIikpICMgb2JqIGQKYiA8LSBiYXNlVmFycwpgYGAKCioqQ29udGV4dCBwb2ludCoqOiBUaGUgYmFzZWxpbmUgZGF0YSBoYXMgYHIgZGltKGIpWzFdYCByb3dzLiBUaGlzIGlzIGByIDI0NDgtZGltKGIpWzFdYCBmZXdlciByb3dzIHRoYW4gd2UgZXhwZWN0ZWQgaW4gdGhlIGJhc2VsaW5lLiBUaGlzIGlzIGJlY2F1c2Ugb2Ygc29tZSBmYXJtZXJzIG5vdCBiZWluZyBzdXJ2ZXllZCBhcyBleHBlY3RlZC4gU2VlIHRoZSBiYXNlbGluZSByZXBvcnQgZm9yIG1vcmUgZGV0YWlscy4gQWxzbywgdGhlc2UgYmFlc2xpbmUgdmFsdWVzIGhhdmUgdGUKCltBbGV4IFZpbGxlY10obWF0aWx0bzphbGV4LnZpbGxlY0BvbmVhY3JlZnVuZC5vcmcpIHdyb3RlIGEgY2xlYW5pbmcgc2NyaXB0IHRvIGRlYWwgd2l0aCB0aGUgZmlyc3Qgcm91bmQgb2YgUndhbmRhIFNIUyBmb2xsb3cgdXAgZGF0YSBhbmQgbWFrZSBrZXkgYWRqdXN0bWVudHMgdG8gdGhlIGRhdGEuIFRvIHV0aWxpemUgdGhhdCBkbyBmaWxlIGhlcmUsIEknbSBnb2luZyB0byBkb3dubG9hZCB0aGUgZGF0YSBmcm9tIENvbW1jYXJlLCBzYXZlIGl0LCBhbmQgaGF2ZSB0aGUgZG9maWxlIGFjY2VzcyB0aGF0IGZpbGUgdG8gZXhlY3V0ZS4gSG93ZXZlciwgdGhlIG9yaWdpbmFsIGZpbGUgQWxleCB3YXMgdXNpbmcgaGFkIGRpZmZlcmVudCB2YXJpYWJsZSBuYW1lcyB0aGFuIHRoZSBmaWxlIHB1bGxlZCBieSB0aGUgQVBJLiBUaGUgb3B0aW9ucyBmcm9tIGhlcmUgYXJlIHRvIGp1c3QgZ28gd2l0aCB0aGUgZmlsZSBmcm9tIEFsZXggb3IgdG8gYWxpZ24gdGhlIHZhcmlhYmxlIG5hbWVzIGJldHdlZW4gaGlzIHZlcnNpb24gYW5kIHRoZSBDQyB2ZXJzaW9uLiBJdCdzIHZhbHVhYmxlIHRvIGhhdmUgdGhlIGRhdGEgZGlyZWN0bHkgZnJvbSBDQyBidXQgaXQnbGwgaW52b2x2ZSBtb3JlIHdvcmsgdXAgZnJvbnQKCiMjIFJvdW5kIDEgZGF0YQoKYGBge3J9CnNvdXJjZSgiLi4vb2FmbGliL2NvbW1jYXJlRXhwb3J0LlIiKQpyIDwtIGdldEZvcm1EYXRhKCJvYWZyd2FuZGEiLCAiTSZFIiwgIjE2QiBVYnV0YWthIChTb2lsKSIsIGZvcmNlVXBkYXRlID0gRikKd3JpdGUuY3N2KHIsIGZpbGU9InJhd0NjUjFEYXRhLmNzdiIsIHJvdy5uYW1lcyA9IEYpCmBgYAoKVGhlIGZpcnN0IHJvdW5kIG9mIGRhdGEgZnJvbSBDb21tQ2FyZSBoYXMgYHIgZGltKHIpWzFdYCBvYnNlcnZhdGlvbnMuIFRoaXMgbGVhdmVzIFhYIG51bWJlciBvZiBmYXJtZXJzIHVuc3VydmV5ZWQgaW4gdGhlIGZpcnN0IHN1cnZleSByb3VuZC4gU2VlIFt0aGlzIGNsZWFuaW5nIGZpbGVdKHd3dy5naXRodWIuY29tKSBmb3IgbW9yZSBpbmZvcm1hdGlvbiBvbiB0aGUgZmFybWVycyB3ZSBkaWQgbm90IGZpbmQgYWdhaW4gaW4gdGhlIGZpcnN0IGZvbGxvdyB1cC4KCkhlcmUgSSdtIGdvaW5nIHRvIGNhbGwgdGhlIFNUQVRBIGNsZWFuaW5nIGZpbGUgdG8gbWFrZSBBVidzIGNoYW5nZXMgdG8gdGhlIFIxIGZvbGxvdyB1cCBkYXRhLiBUaGlzIHJlcXVpcmVzIHRoYXQgdGhlIGRhdGEgZnJvbSBDQyBoYXZlIHRoZSBzYW1lIHZhcmlhYmxlIG5hbWVzIGFzIHRoZSBTVEFUQSBjbGVhbmluZyBmaWxlLiBJJ20gZ29pbmcgdG8gdHJ5IHRvIGV4ZWN1dGUgdGhhdCBoZXJlOgoKYGBge3J9CnN0YXRhRGlyIDwtIG5vcm1hbGl6ZVBhdGgoZmlsZS5wYXRoKCIuLiIsICJyd19yb3VuZF8xX2NoZWNrIikpCmBgYAoKSGVyZSBJIGFjY2VzcyB0aGUgc29pbCBwcmVkaWN0aW9ucyBmcm9tIHRoZSBPQUYgc29pbCBsYWIuIFtQYXRyaWNrIEJlbGxdKG1haWx0bzpwYXRyaWNrLmJlbGxAb25lYWNyZWZ1bmQub3JnKSBtYW5hZ2VzIHRoZSBsYWIgYW5kIFtNaWtlIEJhcmJlcl0obWlrZS5iYXJiZXJAb25lYWNyZWZ1bmQub3JnKSBvdmVyc2VlcyB0aGUgcHJlZGljdGlvbiBzY3JpcHRzLgoKYGBge3J9CnNvaWxEaXIgPC0gbm9ybWFsaXplUGF0aChmaWxlLnBhdGgoIi4uIiwgIi4uIiwgImRhdGEiLCAiT0FGIFNvaWwgTGFiIEZvbGRlciIsICJQcm9qZWN0cyIsICJyd19zaHNfc2Vjb25kX3JvdW5kIiwgIjRfcHJlZGljdGVkIiwgIm90aGVyX3N1bW1hcmllcyIpKQpzb2lsIDwtIHJlYWQuY3N2KGZpbGU9cGFzdGUoc29pbERpciwgImNvbWJpbmVkLXByZWRpY3Rpb25zLWluY2x1ZGluZy1iYWQtb25lcy5jc3YiLCBzZXAgPSAiLyIpKQoKaWREaXIgPC0gbm9ybWFsaXplUGF0aChmaWxlLnBhdGgoIi4uIiwgIi4uIiwgImRhdGEiLCAiT0FGIFNvaWwgTGFiIEZvbGRlciIsICJQcm9qZWN0cyIsICJyd19zaHNfc2Vjb25kX3JvdW5kIiwgIjVfbWVyZ2VkIikpCklkZW50aWZpZXJzIDwtIHJlYWRfZXhjZWwocGFzdGUoaWREaXIsImRhdGFiYXNlLnhsc3giLHNlcD0iLyIpLCBzaGVldD0xKQpgYGAKCkNvbWJpbmUgdGhlIGF2YWlsYWJsZSBkYXRhIGJ5IGZhcm1lciBhbmQgcmVzb2x2ZSBtZXJnaW5nIGlzc3Vlcy4gVGhlc2UgZGF0YSBjYW4gYmUgY29tYmluZWQgbG9uZyBhcyBsb25nIGFzIHRoZSB2YXJpYWJsZSBuYW1lcyBhcmUgY29uc2lzdGVudCBvciB3aWRlLiBJJ20gZ29pbmcgdG8gY29tYmluZSB0aGUgZGF0YSBsb25nIGFuZCB1c2UgYHNwbGl0YCB0eXBlIGNvbW1hbmRzIHRvIGFnZ3JlZ2F0ZSB0aGUgZGF0YSBtb3JlIGVhc2lseS4gQ29uZmlybSB0aGUgdmFyaWFibGUgbmFtZXMgYXJlIGNvbnNpc3RlbnQuIEJ5IGFkdmFuY2luZyB0aGlzIGNvZGUgb24gNS85LzE3LCBJJ20gZm9yIHRoZSB0aW1lIGJlaW5nIGlnbm9yaW5nIHRoZSBjbGVhbmluZyBBbGV4IGRpZCBpbiBoaXMgZG8gZmlsZS4gSSdsbCBuZWVkIHRvIGdvIGJhY2sgYW5kIGluY29ycG9yYXRlIHRob3NlIGNoYW5nZXMuCgoqKlRPRE8qKjogc2VlIGlmIHRoZSB2YXJpYWJsZXMgbmFtZXMgaW4gQWxleCdzIHJhdyBkYXRhLCBzaGFyZWQgYnkgW05hdGhhbmllbF0obWFpbHRvOm5hdGhhbmllbC5yb3NlbmJsdW1Ab25lYWNyZWZ1bmQub3JnKSwgbWF0Y2ggdGhlIGRhdGEgSSdtIGRvd25sb2FkaW5nIGZyb20gY29tbWNhcmUuIElmIHNvLCBkb24ndCB1c2UgdGhlIGB2YXJfbmFtZXMueGxzeGAgc2hlZXQgYW5kIGluc3RlYWQgdXNlIHRob3NlIHZhcmlhYmxlIG5hbWVzIGFuZCBBbGV4J3MgZG8gZmlsZSB0byBwcmVzZXJ2ZSBhbGwgb2YgaGlzIGNoYW5nZXMuCgpOb3QgbWFueSBvZiB0aGUgbmFtZXMgYXJlIHRoZSBzYW1lLiBJJ3ZlIGRvd25sb2FkZWQgdGhlIG1ldGEgZGF0YSBmcm9tIENvbW1DYXJlIHdoaWNoIEknbGwgdXNlIHRvIHNpbXBsaWZ5IHRoZSBjbGVhbmluZyBvZiB0aGUgcm91bmQgMSBkYXRhLiBJJ20gYWxzbyBnb2luZyB0byByZXNoYXBlIHRoZSBiYXNlbGluZSB2YXJpYWJsZSBuYW1lcyB0byBzaW1wbGlmeSB0aGUgbWF0Y2hpbmcgb2YgYmFzZWxpbmUgdmFyaWFibGVzIHRvIHJvdW5kIDEgdmFyaWFibGVzLgpgYGB7ciwgbWVzc2FnZXM9Rn0KZGF0TmFtZXMgPC0gZnVuY3Rpb24oZGF0KXsKICB2YXJOYW1lcyA9IG5hbWVzKGRhdCkKICBleFZhbCA9IGRvLmNhbGwocmJpbmQsIGxhcHBseSh2YXJOYW1lcywgZnVuY3Rpb24oeCl7CiAgICB2YWwgPSBkYXRbMTozLHhdCiAgICByZXR1cm4odmFsKQogIH0pKQogIAogIG91dCA9IGNiaW5kKHZhck5hbWVzLCBleFZhbCkKICByZXR1cm4ob3V0KQp9CgpiYXNlTmFtZXMgPC0gZGF0TmFtZXMoYikKd3JpdGUuY3N2KGJhc2VOYW1lcywgZmlsZT0iYmFzZWxpbmUgdmFyIG5hbWVzLmNzdiIsIHJvdy5uYW1lcyA9IEYpCmBgYAoKTG9hZCBBbGV4J3MgcmF3IGRhdGEgYW5kIHRha2UgdGhlIHZhcmlhYmxlIG5hbWVzIGZyb20gdGhpcy4gSWYgSSBjYW4gYWxpZ24gdGhlc2UgdmFyaWFibGUgbmFtZXMgd2l0aCB0aGUgZGF0YSBmcm9tIENDIEkgY2FuIHRoZW4gZXhlY3V0ZSBBbGV4J3MgY2xlYW5pbmcgc2NyaXB0IG9uIHRoZSBDQyBkYXRhIGFuZCBwcm9jZWVkIHdpdGggY29tYmluaW5nIHRoZSBkYXRhCgojIyBTdGF0YSAuZG8gZmlsZQoKYGBge3J9CnJhd0RpciA8LSBub3JtYWxpemVQYXRoKGZpbGUucGF0aCgiU29pbCBoZWFsdGggc3R1ZHkgKHllYXIgb25lKSIsICJkYXRhIikpCgphdlJhdyA8LSByZWFkLmNzdihwYXN0ZShyYXdEaXIsICJ5MV9zaHNfcndhbmRhXzI4c2VwLmNzdiIsIHNlcCA9ICIvIiksIHN0cmluZ3NBc0ZhY3RvcnMgPSBGKQoKYGBgCgpJdCBsb29rcyBsaWtlIHRoZSBkYXRhIGZyb20gQ29tbUNhcmUgYWxpZ25zIHdpdGggdGhlIHJhdyBkYXRhIEFsZXggd29ya2VkIHdpdGggYXQgYGluZm9fZm9ybWlkYCB3aGljaCBpcyB0aGUgc2Vjb25kIGluZGV4IGZvciBgYXZSYXdgIGFuZCB0aGUgMTB0aCBpbmRleCBmb3IgYHJgLiBMZXQncyBqdXN0IHRyeSB0cmFuc2ZlcnJpbmcgdGhlbSBvdmVyIGFuZCB0aGUgd29yayBvZiB1cGRhdGluZyB0aGUgdmFyaWFibGUgbmFtZXMgdGhyb3VnaCB0aGUgQ0MgY29kZWJvb2sgZXhwb3J0IG1heSBub3QgYmUgbmVjZXNzYXJ5IQoKYGBge3J9CnZhclRlc3QgPC0gZGF0YS5mcmFtZShmcm9tY2MgPSBuYW1lcyhyKVsxMDo0MDldLCBmcm9tYXYgPSBuYW1lcyhhdlJhdylbMjo0MDFdKQojIGhlYWQodmFyVGVzdCkKIyB0YWlsKHZhclRlc3QpCiN2YXJUZXN0WzkwOjEyMCxdCndyaXRlLmNzdih2YXJUZXN0LCBmaWxlPSJ2YXJpYWJsZU5hbWVDaGVjay5jc3YiKQpgYGAKCkl0IHNlZW1zIHRvIGxpbmUgdXAgb2theSAod2l0aCBzb21lIGFkanVzdG1lbnRzKSEgVG8gaW5jb3Jwb3JhdGUgQWxleCdzIGNsZWFuaW5nIGNvZGUgSSBoYXZlIHRvIGV4cG9ydCB0aGUgZGF0YSBmcm9tIFIgdG8gYSBmb3JtIFN0YXRhIGFjY2VwdCwgcnVuIHRoZSBjb2RlLCBhbmQgdGhlbiBsb2FkIHRoZSBkYXRhIGJhY2sgaW4uCgpUaGlzIGZ1bmN0aW9uIHdpbGwgcmVtb3ZlIGFsbCBzdHJhbmdlIG91dHB1dHMgZnJvbSB0aGUgZGF0YSBmcm9tIENvbW1DYXJlIHNvIHRoYXQgdGhlIFNUQVRBIGNvZGUgd29ya3MKCmBgYHtyfQojIGNoYXJDbGVhbiA8LSBmdW5jdGlvbihkZil7CiMgICAKIyAgIGRmIDwtIGFzLmRhdGEuZnJhbWUobGFwcGx5KGRmLCBmdW5jdGlvbih4KXsKIyAgIHggPSBnc3ViKCInIiwgJycsIHgpCiMgICB4ID0gZ3N1YigiXmIiLCAnJywgeCkKIyAgIHggPSBpZmVsc2UoZ3JlcGwoIm1hcCBvYmplY3QiLCB4KT09VCwgTkEsIHgpCiMgICByZXR1cm4oeCkKIyAgIH0pKQojIHJldHVybihkZikKIyB9CiMgCiMgciA8LSBjaGFyQ2xlYW4ocikKYGBgCgpIZXJlIGlzIHdoZXJlIEkgYWN0dWFsbHkgdXBkYXRlIHRoZSBuYW1lcyBpbiBgcmAgdG8gbWF0Y2ggQWxleCdzIG9yaWdpbmFsIGRhdGEuCgpgYGB7cn0KbmFtZXMocilbMTA6NDA5XSA8LSBuYW1lcyhhdlJhdylbMjo0MDFdCgojZXhwb3J0IHNvIHN0YXRhIGNhbiBydW4gLSBjaGVjayBmb3IgdmFyaWFibGUgbmFtZXMgbG9uZ2VyIHRoYW4gMzJjaGFyCnRhYmxlKG5jaGFyKG5hbWVzKHIpKSkKCndyaXRlLmNzdihyLCBmaWxlPSJ0b0JlQ2xlYW5lZFN0YXRhLmNzdiIsIHJvdy5uYW1lcyA9IEYpCgpzdGF0YSgiY2xlYW5zX3kxX3Noc19yd2FuZGEuZG8iLCBzdGF0YS5lY2hvPUYpCmBgYAoKTm93IGxvYWQgdGhlIHJlc3VsdCBvZiB0aGUgU3RhdGEgZmlsZQpgYGB7cn0KciA8LSByZWFkLmNzdigiY2xlYW5lZGZvclIuY3N2Iiwgc3RyaW5nc0FzRmFjdG9ycyA9IEYpCmBgYAoKCiMgQ2xlYW5pbmcKClRoZSBgcmAgZGF0YWZyYW1lIGhhcyBtYW55IG1vcmUgdmFyaWFibGVzIHRoYW4gdGhlIGJhc2VsaW5lIHN1cnZleS4gVGhpcyB3YXMgaW4gcGFydCBleHBlY3RlZDsgd2UgYWRkZWQgcXVlc3Rpb25zIHRvIHRoZSBmaXJzdCBmb2xsb3cgdXAgcm91bmQgYmFzZWQgb24gbGVzc29ucyBmcm9tIHRoZSBiYXNlbGluZS4gSXQncyBhbHNvIGR1ZSB0byBob3cgdGhlIHN1cnZleSB3YXMgc2V0IHVwIGluIENvbW1DYXJlLiBCZWZvcmUgY29tYmluaW5nIHRoZSBiYXNlbGluZSBhbmQgdGhlIGZpcnN0IGZvbGxvdyB1cCByb3VuZCBJIG5lZWQgdG86CgoqIHJlc2hhcGUgdGhlIHJvdW5kIDEgdmFyaWFibGVzIHNvIHRoYXQgdGhleSBhcHByb3ByaWF0ZWx5IG1hdGNoIHRoZSBiYXNlbGluZSB2YXJpYWJsZXMKKiBDbGVhbiB0aG9zZSB2YXJpYWxlcyBvciBwcmVwYXJlIHRoZW0gYXMgbmVlZCBiZSBmb3IgYSAKKiBGb3IgdmFyaWFibGVzIHdpdGggbm8gbWF0Y2gsIGNsZWFuCgojIyBEcm9wIHZhcmlhYmxlcwpgYGB7cn0KdG9Ecm9wIDwtIGMoImFwcGZvcm1pZCIsICJpZCIsICJkb21haW4iLCAibWV0YWRhdGFkZXZpY2VpZCIpCnIgPC0gclssIW5hbWVzKHIpICVpbiUgdG9Ecm9wXQpgYGAKCgpgYGB7cn0Kc291cmNlKCIuLi9vYWZsaWIvbWlzYy5SIikKbmFtZXMocikgPC0gZ3N1YigiXnkxX3xpbnRyb18iLCAiIiwgbmFtZXMocikpCnJbcj09Ii4iXSA8LSBOQQoKciA8LSBkaXZpZGVHcHMociwgImdwc19jb29yZCIpCmBgYAoKIyMgQ2F0ZWdvcmljYWwgdmFyaWFibGVzCgpUaGUgcmVzcG9uc2VzIG9mIHRoZSBjYXRlZ29yaWNhbCB2YXJpYWJsZXMgc2hvdWxkIGJlIHJlZ3VsYXRlZCB0aHJvdWdoIENDLCBob3dldmVyLCB0byBjaGVjaywgbWFrZSBhIHRhYmxlIHRoYXQgc2hvd3MgdGhlIHRvcCB0ZW4gcmVzcG9uc2VzIGluIGRlc2NlbmRpbmcgb3JkZXIgYW5kIG1ha2UgYSBncmFwaCBvZiByZXNwb25zZSBjb3VudHMgdG8ga25vdyB3aGF0IHRvIGNoZWNrLiBJJ2xsIHRoZW4gY2FwdHVyZSBhbnkgY2hhcmFjdGVycyB0aGF0IHNob3VsZCBiZSBudW1lcmljIGFuZCBjb252ZXJ0IHRoZW0uCgpgYGB7cn0KY2F0VmFycyA8LSBuYW1lcyhyKVtzYXBwbHkociwgZnVuY3Rpb24oeCl7CiAgaXMuY2hhcmFjdGVyKHgpCn0pXQoKZW51bUNsZWFuIDwtIGZ1bmN0aW9uKGRhdCwgeCwgdG9SZW1vdmUpewogIGRhdFsseF0gPC0gaWZlbHNlKGRhdFsseF0gJWluJSB0b1JlbW92ZSwgTkEsIGRhdFsseF0pCiAgcmV0dXJuKGRhdFsseF0pCn0KCnN0clRhYmxlIDwtIGZ1bmN0aW9uKGRhdCwgeCl7CiAgdmFyTmFtZSA9IHgKICB0YWIgPSBhcy5kYXRhLmZyYW1lKHRhYmxlKGRhdFsseF0sIHVzZU5BID0gJ2lmYW55JykpCiAgdGFiID0gdGFiW29yZGVyKHRhYiRGcmVxLCBkZWNyZWFzaW5nID0gVCksXQogIGVuZCA9IGlmZWxzZShsZW5ndGgodGFiJFZhcjEpPDEwLCBsZW5ndGgodGFiJFZhcjEpLCAxMCkKICByZXBPcmRlciA9IHBhc3RlKHRhYiRWYXIxWzE6ZW5kXSwgY29sbGFwc2U9IiwgIikKICBvdXQgPSBkYXRhLmZyYW1lKHZhcmlhYmxlID0gdmFyTmFtZSwKICAgICAgICAgICAgICAgICAgIHJlc3BvbnNlcyA9IHJlcE9yZGVyKQogIAogIHJldHVybihvdXQpCn0KCiMgY2xlYW4gdXAga25vd24gdmFsdWVzCmNhdEVudW1WYWxzIDwtIGMoIi05OSIsICItODgiLCAiLSA5OSIsICItOTkuMCIsICI4OCIsICJfODgiLCAiLSA4OCIsICIwLjg4IiwKICAgICAgICAgICAgICAgICAiLS04OCIsICJfXzg4IiwgIi04OC4wIiwgIjk5LjAiKQpyWyxjYXRWYXJzXSA8LSBzYXBwbHkoY2F0VmFycywgZnVuY3Rpb24oeSl7CiAgclsseV0gPC0gZW51bUNsZWFuKHIseSwgY2F0RW51bVZhbHMpCn0pCgoKcmVzcG9uc2VUYWJsZSA8LSBkby5jYWxsKHJiaW5kLCBsYXBwbHkoY2F0VmFycywgZnVuY3Rpb24oeCl7CiAgc3RyVGFibGUociwgeCkKfSkpCgpgYGAKCiMjIyBDYXRlZ29yaWNhbCByZXNwb25zZSB0YWJsZQoKQSBzaW1wbGUgdGFibGUgdG8gcHJldmlldyB0aGUgdmFsdWVzIGluIHRoZSBkYXRhLiBUaGUgdmFsdWVzIGFyZSByYW5rZWQgYnkgZnJlcXVlbmN5LgoKYGBge3J9CmthYmxlKHJlc3BvbnNlVGFibGUpCmBgYAoKIyMjIENhdGVnb3JpY2FsIHJlc3BvbnNlIGdyYXBocwpgYGB7cn0KcmVwR3JhcGhzIDwtIGZ1bmN0aW9uKGRhdCwgeCl7CiAgdGFiID0gYXMuZGF0YS5mcmFtZSh0YWJsZShkYXRbLHhdLCB1c2VOQSA9ICdpZmFueScpKQogIHRhYiA9IHRhYltvcmRlcih0YWIkRnJlcSwgZGVjcmVhc2luZyA9IFQpLF0KICBwcmludCgKICAgIGdncGxvdChkYXRhPXRhYiwgYWVzKHg9VmFyMSwgeT1GcmVxKSkgKyBnZW9tX2JhcihzdGF0PSJpZGVudGl0eSIpICsKICAgICAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gImJvdHRvbSIsIGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gNDUsIGhqdXN0ID0gMSkpICsKICAgICAgbGFicyh0aXRsZSA9cGFzdGUwKCJDb21wb3NpdGlvbiBvZiB2YXJpYWJsZTogIiwgeCkpCiAgKQp9CgphZG1pblZhcnMgPC0gYyhuYW1lcyhyKVtncmVwKCJtZXRhIiwgbmFtZXMocikpXSwgInN0YXJ0X3RpbWUiLCAiZW51bV9uYW1lIiwgInBob3RvIiwgImNlbGxfZmllbGQiLCAidmlsbGFnZSIsICJmYXJtZXJfcmVzcG9uZCIsICJmYXJtZXJfcGhvbmVudW1iZXIiLCAiZF9waG9uZSIsICJuZWlnaGJvcl9waG9uZW51bWJlciIsICJmYXJtZXJfbGlzdCIsICJ1bmlxdWVfbG9jYXRpb24iLCAiY29tbWVudHMiLCAiZ3BzX2Nvb3JkIiwgInNhbXBsZV9pZCIsICJTU04iKQpub25BZG1pblZhcnMgPC0gY2F0VmFyc1shY2F0VmFycyAlaW4lIGFkbWluVmFyc10KCmZvcihpIGluIDE6bGVuZ3RoKG5vbkFkbWluVmFycykpewogIHJlcEdyYXBocyhyLCBub25BZG1pblZhcnNbaV0pCn0KYGBgCgojIyMgTWFudWFsIGNoYXJhY3RlciBjbGVhbmluZwpgYGB7cn0KciRmZW1hbGUgPC0gaWZlbHNlKHIkZ2VuZGVyPT0iZmVtYWxlIiwgMSwgMCkKciRkaXN0cmljdCA8LSBpZmVsc2UoZ3JlcGwoIm55YW56YSIsIHIkZGlzdHJpY3QpPT1ULCAiTnlhbnphIiwgciRkaXN0cmljdCkKCiN0YWJsZShyJGtnX3NlZWRfMTZiXzEpCiN0YWJsZShyJGtnX3lpZWxkXzE2YV8yKQoKc3RydG9OdW0gPC0gYygia2dfc2VlZF8xNmJfMSIsICJrZ195aWVsZF8xNmFfMSIsICJrZ195aWVsZF8xNmJfMSIsICJrZ195aWVsZF8xNmJfMiIpCnJbLHN0cnRvTnVtXSA8LSBzYXBwbHkoclssc3RydG9OdW1dLCBmdW5jdGlvbih4KXthcy5udW1lcmljKHgpfSkKYGBgCgojIyMgQ2F0ZWdvcmljYWwgY2xlYW5pbmcKClRPRE8gaGVyZSEKCk5vdGVzIG9uIHRoZSBjYXRlZ29yaWNhbCB2YXJpYWJsZXM6CgoqIFdlIGRvbid0IGhhdmUgbWFueSBhY3R1YWwgcmVzcG9uc2VzIG9uIHNlZWQgdHlwZSBkZXNwaXRlIGFsbCBmYXJtZXJzIHRlbGxpbmcgdXMgYWJvdXQgYSBjcm9wIHRoZXkgYXJlIGdyb3dpbmcuIFdoeT8gQ2hlY2sgdGhhdCB0aGVyZSB3YXNuJ3QgYSBtaXNsYWJlbGluZyBvZiB2YXJpYWJsZXMuCiogQ2hlY2sgdGhlICd3aGljaF9tYWl6ZV9zZWVkJyB2YXJpYWJsZXMgdG8gbWFrZSBjZXJ0YWluIHRoZXkncmUgZmxleGlibGUgdG8gdGhlIHR5cGUgb2YgY3JvcCBzZWxlY3RlZCBpbiB0aGUgcHJldmlvdXMgcXVlc3Rpb24uCiogQ29uZmlybSB0aGF0IGJsYW5rIGlzIE5BIG5vdCAwLgoKIyMgTnVtZXJpYyB2YXJpYWJsZXMKCmBgYHtyfQpudW1WYXJzIDwtIG5hbWVzKHIpW3NhcHBseShyLCBmdW5jdGlvbih4KXsKICBpcy5udW1lcmljKHgpCn0pXQpgYGAKCkJhc2ljIGNsZWFuaW5nIG9mIGtub3duIGlzc3VlcyBsaWtlIGVudW1lcmF0b3IgY29kZXMgZm9yIERLLCBOV1IsIGV0Yy4KYGBge3J9CmVudW1WYWxzIDwtIGMoLTg4LC04NSwgLTk5KQoKclssbnVtVmFyc10gPC0gc2FwcGx5KG51bVZhcnMsIGZ1bmN0aW9uKHkpewogIHJbLHldIDwtIGVudW1DbGVhbihyLHksIGVudW1WYWxzKQp9KQpgYGAKCiMjIyBOdW1lcmljIG91dGxpZXIgdGFibGUKCmBgYHtyfQppcXIuY2hlY2sgPC0gZnVuY3Rpb24oZGF0LCB4KSB7IAogIHExID0gc3VtbWFyeShkYXRbLHhdKVtbMl1dCiAgcTMgPSBzdW1tYXJ5KGRhdFsseF0pW1s1XV0gCiAgaXFyID0gcTMtcTEKICBtYXJrICA9IGlmZWxzZShkYXRbLHhdIDwgKHExIC0gKDEuNSppcXIpKSB8IGRhdFsseF0gPiAocTMgKyAoMS41KmlxcikpLCAxLDApCiAgdGFiID0gcmJpbmQoCiAgICBzdW1tYXJ5KGRhdFsseF0pLAogICAgc3VtbWFyeShkYXRbbWFyaz09MCwgeF0pCiAgKQogIHJldHVybih0YWIpCn0KCiMgcmVtb3ZlIGFkbWluIHZhcnMKbnVtQWRtaW5WYXJzIDwtIGMobnVtVmFyc1sxOjNdKQpudW1WYXJzTm90QWRtaW4gPC0gbnVtVmFyc1shbnVtVmFycyAlaW4lIG51bUFkbWluVmFyc10KCmlxclRhYiA8LSBkby5jYWxsKHBseXI6OnJiaW5kLmZpbGwsIGxhcHBseShudW1WYXJzTm90QWRtaW4sIGZ1bmN0aW9uKHkpewogICNwcmludCh5KQogIHJlcyA9IGlxci5jaGVjayhyLCB5KQogICNwcmludChkaW0ocmVzKSkKICBvdXQgPSBkYXRhLmZyYW1lKHZhcj1yYmluZCh5LCBwYXN0ZSh5LCAiLmlxciIsIHNlcD0iIikpLCByZXMpCiAgcmV0dXJuKG91dCkKfSkpCgppcXJUYWJbLDI6OF0gPC0gc2FwcGx5KGlxclRhYlssMjo4XSwgZnVuY3Rpb24oeCl7cm91bmQoeCwxKX0pCmBgYAoKVGhlIG91dGxpZXIgdGFibGUgc3VtbWFyaXplcyB0aGUgbnVtZXJpYyB2YXJpYWJsZXMgd2l0aCBhbmQgd2l0aG91dCBJUVIgb3V0bGllcnMgdG8gc2hvdyBob3cgdGhlIGRhdGEgY2hhbmdlcyBiYXNlZCBvbiB0aGlzIGZpbHRlci4KCmBgYHtyfQprbml0cjo6a2FibGUoaXFyVGFiLCByb3cubmFtZXMgPSBGLCBkaWdpdHMgPSAwLCBmb3JtYXQgPSAnbWFya2Rvd24nKQpgYGAKCiMjIyBPdXRsaWVyIEdyYXBocwpgYGB7cn0KIyBodHRwOi8vcmZvcnB1YmxpY2hlYWx0aC5ibG9nc3BvdC5jb20vMjAxNC8wMi9nZ3Bsb3QyLWNoZWF0c2hlZXQtZm9yLXZpc3VhbGl6aW5nLmh0bWwKZm9yKGkgaW4gMTpsZW5ndGgobnVtVmFyc05vdEFkbWluKSl7CiAgICBiYXNlIDwtIGdncGxvdChyLCBhZXMoeD1yWyxudW1WYXJzTm90QWRtaW5baV1dKSkgKyBsYWJzKHggPSBudW1WYXJzTm90QWRtaW5baV0pCiAgICB0ZW1wMSA8LSBiYXNlICsgZ2VvbV9kZW5zaXR5KCkKICAgIHRlbXAyIDwtIGJhc2UgKyBnZW9tX2hpc3RvZ3JhbSgpCiAgICAjdGVtcDIgPC0gYm94cGxvdChyWyxudW1WYXJzW2ldXSxtYWluPXBhc3RlMCgiVmFyaWFibGU6ICIsIG51bVZhcnNbaV0pKQogICAgbXVsdGlwbG90KHRlbXAxLCB0ZW1wMiwgY29scyA9IDIpCn0KYGBgCgojIyMgTnVtZXJpYyB2YXJpYWJsZSBjbGVhbmluZwoKVE9ETyBoZXJlIQoKIyMgTWVyZ2UgaW4gc29pbCBkYXRhCgpGaXJzdCBtZXJnZSB0aGUgc29pbCBkYXRhIHdpdGggdGhlIGlkZW50aWZpZXJzIGFzIHdlIHNob3VsZCBnZXQgZnVsbCBtYXRjaGVzLiBUaGVuIG1lcmdlIHNvaWwgZGF0YSB0byB0aGUgc3VydmV5IGRhdGEKCmBgYHtyfQpJZGVudGlmaWVycyA8LSBJZGVudGlmaWVycyAlPiUgcmVuYW1lKAogIHNhbXBsZV9pZCA9IGBTYW1wbGUgSURgLAogIFNTTiA9IGBMYWIgc3NuYAopICU+JSBtdXRhdGUoCiAgc2FtcGxlX2lkID0gZ3N1YigiICIsICIiLCB0b2xvd2VyKHNhbXBsZV9pZCkpCikKCnRhYmxlKElkZW50aWZpZXJzJFNTTiAlaW4lIHNvaWwkU1NOKSAjIGZ1bGwgbWF0Y2hlcwoKc29pbCA8LSBsZWZ0X2pvaW4oc29pbCwgSWRlbnRpZmllcnNbLCBjKCJTU04iLCAic2FtcGxlX2lkIildLCBieT0iU1NOIikgCmBgYAoKV2UgaGF2ZSBzb21lIHN1cnZleXMgdGhhdCBkb24ndCBoYXZlIHNvaWwgZGF0YS4gSXQgc2VlbXMgdGhlIHNvaWwgc2FtcGxlIGlkIGluIHRoZSBgSWRlbnRpZmllcnNgIGRhdGEgYXJlIGEgYml0IG1lc3N5LiBMZXQncyBjbGVhbiBib3RoIHVwIGFib3ZlIGJ5IHJlbW92aW5nIHNwYWNlcyBhbmQgbWFraW5nIGxvd2VyIGNhc2UuCgpgYGB7cn0KciRzYW1wbGVfaWQgPC0gdG9sb3dlcihyJHNhbXBsZV9pZCkKCnRhYmxlKHIkc2FtcGxlX2lkICVpbiUgc29pbCRzYW1wbGVfaWQpCnIkc2FtcGxlX2lkWyFyJHNhbXBsZV9pZCAlaW4lIHNvaWwkc2FtcGxlX2lkXQoKd3JpdGUuY3N2KHIkc2FtcGxlX2lkWyFyJHNhbXBsZV9pZCAlaW4lIHNvaWwkc2FtcGxlX2lkXSwgInN1cnZleXNXb1NvaWwuY3N2Iiwgcm93Lm5hbWVzID0gRikKYGBgCgpBbmQgc29tZSBzb2lsIHNhbXBsZV9pZCB0aGF0IGRvbid0IGhhdmUgYSBzdXJ2ZXkKYGBge3J9CnNvaWwkc2FtcGxlX2lkWyFzb2lsJHNhbXBsZV9pZCAlaW4lIHIkc2FtcGxlX2lkXQp3cml0ZS5jc3Yoc29pbCRzYW1wbGVfaWRbIXNvaWwkc2FtcGxlX2lkICVpbiUgciRzYW1wbGVfaWRdLCAic29pbHNXb1N1cnZleS5jc3YiLCByb3cubmFtZXMgPSBGKQpgYGAKCmBgYHtyfQpkaW0ocikKciA8LSBsZWZ0X2pvaW4ociwgc29pbCwgYnk9InNhbXBsZV9pZCIpCmRpbShyKSAjIHdoeSBpcyBpdCBvbmUgcm93IGxvbmdlciBhZnRlciB0aGUgbGVmdF9qb2luPwpgYGAKCgojIyBTb2lsIHZhbHVlcwpgYGB7cn0KZ2dwbG90KHIsIGFlcyh4PUNhbGNpdW0sIHk9TWFnbmVzaXVtKSkgKyBnZW9tX3BvaW50KCkgKwogICAgc3RhdF9zbW9vdGgobWV0aG9kPSJsb2VzcyIpICsKICAgIGxhYnMoeCA9ICJDYWxjaXVtIChtMykiLCB5PSAiTWFnbmVzaXVtIChtMykiLCB0aXRsZT0iQ2FsY2l1bSBhbmQgTWFnbmVzaXVtIHJlbGF0aW9uc2hpcCIpCgpnZ3Bsb3QociwgYWVzKHg9cEgsIHk9Q2FsY2l1bSkpICsgZ2VvbV9wb2ludCgpICsKICBzdGF0X3Ntb290aChtZXRob2Q9ImxvZXNzIikgKwogIGxhYnMoeCA9ICJwSCIsIHk9IkNhbGNpdW0gKG0zKSIsIHRpdGxlID0gInBIIGFuZCBDYWxjaXVtIHJlbGF0aW9uc2hpcCIpCgpnZ3Bsb3QociwgYWVzKHg9cEgsIHk9TWFnbmVzaXVtKSkgKyBnZW9tX3BvaW50KCkgKwogIHN0YXRfc21vb3RoKG1ldGhvZD0ibG9lc3MiKSArCiAgbGFicyh4ID0gInBIIiwgeT0iTWFnbmVzaXVtIChtMykiLCB0aXRsZSA9ICJwSCBhbmQgTWFnbmVzaXVtIHJlbGF0aW9uc2hpcCIpCgpnZ3Bsb3QociwgYWVzKHg9cEgsIHk9WC5FeGNoYW5nZWFibGUuQWNpZGl0eSkpICsgZ2VvbV9wb2ludCgpICsKICBzdGF0X3Ntb290aChtZXRob2Q9ImxvZXNzIikgKwogIGxhYnMoeCA9ICJwSCIsIHk9IkV4Y2hhbmdlYWJsZSBBbHVtaW51bSIsIHRpdGxlID0gInBIIGFuZCBBbHVtaW51bSByZWxhdGlvbnNoaXAiKQoKZ2dwbG90KHIsIGFlcyh4PVguT3JnYW5pYy5DYXJib24sIHk9WC5Ub3RhbC5OaXRyb2dlbikpICsgZ2VvbV9wb2ludCgpICsgCiAgc3RhdF9zbW9vdGgobWV0aG9kPSJsb2VzcyIpICsKICBsYWJzKHggPSAiVG90YWwgQ2FyYm9uIiwgeT0iVG90YWwgTml0cm9nZW4iLCB0aXRsZSA9ICJDYXJib24gYW5kIE5pdHJvZ2VuIHJlbGF0aW9uc2hpcCIpCgpnZ3Bsb3QociwgYWVzKHg9cEgsIHk9WC5FeGNoYW5nZWFibGUuQWNpZGl0eSkpICsgZ2VvbV9wb2ludCgpICsgCiAgc3RhdF9zbW9vdGgobWV0aG9kPSJsb2VzcyIpICsKICBzY2FsZV94X2NvbnRpbnVvdXMoYnJlYWtzPXNlcSg0LDgsMC41KSkgKwogIGxhYnMoeCA9ICJwSCIsIHk9IkV4Y2hhbmdlYWJsZSBBY2lkaXR5IiwgdGl0bGUgPSAicEggLyBFeEFjIikKCgpgYGAKCmBgYHtyfQpzb2lsVmFycyA8LSBuYW1lcyhyKVt3aGljaChuYW1lcyhyKT09InBIIik6d2hpY2gobmFtZXMocik9PSJYLlRvdGFsLk5pdHJvZ2VuIildCmtleVNvaWxWYXJzIDwtIGMoInBIIiwgIlguT3JnYW5pYy5DYXJib24iLCAiWC5Ub3RhbC5OaXRyb2dlbiIsICJDYWxjaXVtIiwgIk1hZ25lc2l1bSIpCndyaXRlLmNzdihzb2lsVmFycywgZmlsZT0ic29pbFZhcnNmb3JTdGVwLmNzdiIsIHJvdy5uYW1lcyA9IEYpCmBgYAoKIyMjIEluaXRpYWwgVCB2cy4gQyBzb2lsIGNvbXBhcmlzb24KCioqUGxlYXNlIG5vdGUqKjogVGhlc2UgYXJlIHJhdyBjb21wYXJpc29ucyB1c2luZyBvbmx5IHJvdW5kIDEgZGF0YSBhbmQgdGh1cyBzaG91bGQgbm90IGJlIHRha2VuIGFzIGluaXRpYWwgZmluZGluZ3MgZm9yIGhvdyBUIGFuZCBDIGZhcm1lcnMgY29tcGFyZS4gRmFybWVycyB3aWxsIGJlIG1hdGNoZWQgdG8gZW5zdXJlIGEgcHJvcGVyIGNvbXBhcmlzb24uCgpgYGB7cn0KZm9yKGkgaW4gMTpsZW5ndGgoc29pbFZhcnMpKXsKICBwMSA8LSBnZ3Bsb3QoZGF0YT1yLCBhZXMoeD1hcy5mYWN0b3IoZF9jbGllbnRfMTZiKSwgeT1yWyxzb2lsVmFyc1tpXV0pKSArIAogICAgZ2VvbV9ib3hwbG90KCkgKwogICAgbGFicyh4PSJUdWJ1cmEgRmFybWVyIiwgeT1zb2lsVmFyc1tpXSkKICBwMiA8LSBnZ3Bsb3QoZGF0YT1yLCBhZXMoeD1yWyxzb2lsVmFyc1tpXV0pKSArIAogICAgZ2VvbV9kZW5zaXR5KCkgKyAKICAgIGxhYnMoeD1zb2lsVmFyc1tpXSkKICBtdWx0aXBsb3QocDEsIHAyLCBjb2xzPTIpCn0KCgpgYGAKCiMjIyBTb2lsIG5vdGVzIGZvciBQYXRyaWNrIGFuZCBTdGVwCgoqIFRoZSBjYXJib24gdnMuIG5pdHJvZ2VuIHNjYXR0ZXIgcGxvdCBsb29rcyBvZGQgaW4gdGhhdCB0aGUgdmFsdWVzIGFyZSBjbHVtcGVkIGluIGRpc2NyZXRlIGxpbmVzLiBXaHkgbWlnaHQgdGhhdCBiZT8KKiBXaGF0IGFyZSBhcHByb3ByaWF0ZSBjdXRvZmYgdmFsdWVzIGZvciB0aGUgbGFiIHByZWRpY3Rpb25zPyAoUGF0cmljaywgYXMgYSBnZW5lcmFsIHF1ZXN0aW9uLCB3ZSBzaG91bGQgcHJvYmFibHkgYXBwbHkgdGhvc2UgY3V0b2ZmcyB0byBhbnkgbGFiIGRhdGEgYmVmb3JlIHNoYXJpbmcgaXQgd2l0aCB0aGUgdGVhbXMgdG8gc2ltcGxpZnkgd29ya2luZyB3aXRoIHRob3NlIGRhdGEpCgojIyMgU29pbCB2YWx1ZSBjbGVhbmluZwoKU3RlcCBhbmQgUGF0cmljayBzYXkgdGhhdCBpdCdzIGhhcmQgdG8gc2V0IGhhcmQgYW5kIGZhc3QgZ3VpZGVsaW5lcyBmb3Igd2hhdCBhcmUgYW5kIGFyZSBub3QgcmVhc29uYWJsZSB2YWx1ZXMuIEknbSB0aGVyZWZvcmUgZ29pbmcgdG8gc2VlIHdoYXQgaGFwcGVucyB0byB0aGUgZGF0YSBpZiB3ZSB0cmltIGJ5IHNkIGFuZCBJUVIgYW5kIHRoZW4gYXBwbHkgb25lIG9mIHRob3NlIGFkanVzdG1lbnRzIHRvIHRoZSBkYXRhLgoKYGBge3J9CmNoZWNrLjNzZCA8LSBmdW5jdGlvbih4KSB7CiAgeCA9IGlmZWxzZShpcy5pbmZpbml0ZSh4KSwgTkEsIHgpCiAgbWVhbiA9IG1lYW4oeCwgbmEucm09VCkKICBzZCA9IHNkKHgsIG5hLnJtPVQpCiAgbWFyayA9IGlmZWxzZSh4PihtZWFuICsgKDMqc2QpKSB8CiAgICAgICAgeDwobWVhbiAtICgzKnNkKSksIE5BLCB4KQogIHJldHVybihtYXJrKQp9CgoKc2RTb2lsVmFscyA8LSByICU+JQogIGRwbHlyOjpzZWxlY3QocEg6WC5Ub3RhbC5OaXRyb2dlbikgCgpzZENoZWNrIDwtIGFzLmRhdGEuZnJhbWUoYXBwbHkoc2RTb2lsVmFscywgMiwgZnVuY3Rpb24oeCl7CiAgcmV0dXJuKGNoZWNrLjNzZCh4KSkKfSkpCmBgYAoKYGBge3J9CmZvcihpIGluIDE6bGVuZ3RoKHNvaWxWYXJzKSl7CiAgcHJpbnQoZ2dwbG90KGRhdGE9c2RDaGVjaywgYWVzKHg9c2RDaGVja1ssc29pbFZhcnNbaV1dKSkgKyAKICAgIGdlb21fZGVuc2l0eSgpICsgCiAgICBsYWJzKHg9c29pbFZhcnNbaV0pCiAgKQp9CgpgYGAKCioqSW1wb3J0YW50IG5vdGUqKjogSSdtIGdvaW5nIHRvIGFkZCB0aGUgYWRqdXN0ZWQgdmFsdWVzIHRvIHRoZSBgcmAgZGF0YSBmcmFtZSBnaXZpbmcgdGhlIHByZXZpb3VzIHZhcmlhYmxlcyB0aGUgZXh0ZW5zaW9uIGAucmF3YCBzbyBJIGNhbiBkaXN0aW5ndWlzaCBiZXR3ZWVuIHRoZSBvcmlnaW5hbCBhbmQgbW9kaWZpZWQgZGF0YS4KCmBgYHtyfQpuYW1lcyhyKVt3aGljaChuYW1lcyhyKT09InBIIik6d2hpY2gobmFtZXMocik9PSJYLlRvdGFsLk5pdHJvZ2VuIildIDwtIHBhc3RlMChuYW1lcyhyKVt3aGljaChuYW1lcyhyKT09InBIIik6d2hpY2gobmFtZXMocik9PSJYLlRvdGFsLk5pdHJvZ2VuIildLCAiLnJhdyIpCgpyIDwtIGNiaW5kKHIsIHNkQ2hlY2spCmBgYAoKCiMjIENoZWNrIGZvciB1bmlxdWUgaWRzCgpJJ20gc2VlaW5nIHRoYXQgdGhlcmUgYXJlIGR1cGxpY2F0ZWQgZmFybWVycyBpbiB0aGUgZGF0YSB3aGVuIEknbSB0cnlpbmcgdG8gcmVzaGFwZSB0aGUgYHJgIGRhdGEgZnJvbSB3aWRlIHRvIGxvbmcuIExldCdzIGNoZWNrIHRoZW0gb3V0IGhlcmUgYW5kIHNlZSBpZiB3ZSBjYW4gZmlndXJlIG91dCB3aGljaCBvYnNlcnZhdGlvbiBpcyByaWdodC4gCgoqIENoZWNrIEFsZXgncyBkbyBmaWxlIHRvIHNlZSBpZiB0aGVyZSdzIG1lbnRpb24gb2YgdGhlc2UgZmFybWVycy4gW05vIG1lbnRpb25dCiogQ2hlY2sgdGhlIGJhc2VsaW5lIHZhbHVlcyBhcyB0aGVzZSBzaG91bGQgbGluZSB1cC4KCmBgYHtyfQpsZW5ndGgociRzYW1wbGVfaWQpPT1sZW5ndGgodW5pcXVlKHIkc2FtcGxlX2lkKSkKZHVwcyA8LSByJHNhbXBsZV9pZFtkdXBsaWNhdGVkKHIkc2FtcGxlX2lkKV0KZHVwSW5kZXggPC0gd2hpY2goZHVwbGljYXRlZChyJHNhbXBsZV9pZCkpCgojZHVwRGF0IDwtIHJbciRzYW1wbGVfaWQgJWluJSBkdXBzLF0KI2hlYWQocltyJHNhbXBsZV9pZD09ZHVwc1sxXSxdKQojaGVhZChyW3Ikc2FtcGxlX2lkPT1kdXBzWzJdLF0pCmBgYAoKTGV0J3Mgc29sdmUgdGhlIHVuaXF1ZSBpZCBpc3N1ZSBieSBsb29raW5nIGF0IGlkZW50aWZ5aW5nIGluZm9ybWF0aW9uIGluIHRoZSBiYXNlbGluZSBkYXRhCmBgYHtyfQoKcm91bmRJZCA8LSByICU+JQogIGRwbHlyOjpzZWxlY3QoZGlzdHJpY3QsIGNlbGxfZmllbGQsIHZpbGxhZ2UsIHNhbXBsZV9pZCwgZmFybWVyX2xpc3QpICU+JQogIGZpbHRlcihyJHNhbXBsZV9pZCAlaW4lIGR1cHMpCgoKCiNkCmxvYWQoInJhd0Jhc2VsaW5lV2l0aElkZW50aWZlcnMuUmRhdGEiKQpiYXNlSWQgPC0gZCAlPiUgCiAgZHBseXI6OnNlbGVjdChkaXN0cmljdCwgc2VsZWN0ZWRfY2VsbCwgdW11ZHVndWR1LCAgc2FtcGxlX2lkLCBmYXJtZXJfbmFtZSApICU+JQogIGZpbHRlcihkJHNhbXBsZV9pZCAlaW4lIGR1cHMpCgojYmFzZUlkCiNyb3VuZElkCgpgYGAKCiMjIyBDb3JyZWN0IGR1cGxpY2F0ZXMKCkNvcnJlY3QgdGhlIGR1cGxpY2F0ZXMgSSBjYW4gYW5kIGRyb3AgdGhlIG90aGVycyBmb3Igbm93LiBGbGFnIHRoZSBkdXBsaWNhdGVkIG9uZXMgYW5kIHNhdmUgdGhlbSB0byBzaGFyZSB3aXRoIE5hdGhhbmllbC4KClRPRE8obWF0dGxvd2VzKSAtIHNoYXJlIGFueSByZW1haW5pbmcgZHVwbGljYXRlcyB3aXRoIE5hdGhhbmllbCBhbmQgc2VlIGlmIGhlIGhhcyBhIHNvbHV0aW9uLiBBbHNvIHNlZSBpZiBoZSBjYW4gdW5kZXJzdGFuZCB3aHkgdGhpcyBtaWdodCBoYXZlIGhhcHBlbmVkIGFuZCBpZiB0aGV5IHNob3VsZCBhY3R1YWxseSBoYXZlIGEgZGlmZmVyZW50IHNhbXBsZSBpZC4KCiogc2hhcmUgdGhlIG1lcmdlZCBkYXRhIGZvciBOYXRoYW5pZWwgdG8gcHV0IGludG8gQ0MgKGluY2x1ZGUgdGhlIGR1cGxpY2F0ZSBpZHMpCgpgYGB7cn0KciA8LSByICU+JSBtdXRhdGUoCiAgICBkdXAgPSBpZmVsc2UoCiAgICAgIHNhbXBsZV9pZCA9PSAiMTIiICYgY2VsbF9maWVsZCA9PSAiTVVOQU5JUkEiIHwKICAgICAgc2FtcGxlX2lkID09ICIxMzciICYgdmlsbGFnZSA9PSAiUnVzdW1hIiB8CiAgICAgIHNhbXBsZV9pZCA9PSAiMTUwMyIgJiBmYXJtZXJfbGlzdD09Ik5BS0FHSVpFIFZhbFxceGMzXFx4YTlyaWUiIHwKICAgICAgI3NhbXBsZV9pZCA9PSAiMjA0NEMiICYgICMgc2FtZSEKICAgICAgc2FtcGxlX2lkID09ICIyMjc4IiAmIGNlbGxfZmllbGQ9PSJOa2lyYSBBIiB8ICMgY2hlY2sgdGhpcyBhcyBtYXliZSB0aGlzIHdhcyB0aGUgb25seSB0aGluZyB3cm9uZz8KICAgICAgI3NhbXBsZV9pZCA9PSAiMjI5OSIgJiAjIHNhbWUhCiAgICAgIHNhbXBsZV9pZCA9PSAiMjYxMCIgJiB2aWxsYWdlPT0iYWdha2lyaSIgI3wgICNhZ2FraXJpIGlzIGNsb3NlIHRvIGdha2lyaSBpbiBzcGVsbGluZy4gSXMgdGhpcyBqdXN0IGEgdHlwbz8KICAgICAgI3NhbXBsZV9pZCA9PSAiMjYxMiIgJiAgIyBzYW1lIG5hbWVzIQogICAgICAjc2FtcGxlX2lkID09ICIyNjEyQyIgIyBzYW1lIG5hbWVzIQogICAgICAsIDEsIDApCikgJT4lIGZpbHRlcigKICBkdXAhPTEKKSAlPiUgZHBseXI6OnNlbGVjdCgtZHVwKSAKCiMgcnVuIHRoaXMgY29kZSBhZ2FpbiBmcm9tIGFib3ZlIHRvIGdldCB1cGRhdGVkIGR1cGxpY2F0ZXMgbGlzdAojbGVuZ3RoKHIkc2FtcGxlX2lkKT09bGVuZ3RoKHVuaXF1ZShyJHNhbXBsZV9pZCkpCmR1cHMgPC0gciRzYW1wbGVfaWRbZHVwbGljYXRlZChyJHNhbXBsZV9pZCldCmR1cEluZGV4IDwtIHdoaWNoKGR1cGxpY2F0ZWQociRzYW1wbGVfaWQpKQoKIyBmb3IgdGhlIHRpbWUgYmVpbmcgZHJvcCB0aGUgb2JzZXJ2YXRpb25zIHRoYXQgYXJlIGR1cGxpY2F0ZXMKciA8LSByWyFyJHNhbXBsZV9pZCAlaW4lIGR1cHMsXQoKYGBgCgojIyBSZXNoYXBlIHZhcmlhYmxlcwoKVGhpcyBzaG91bGQgaW5jbHVkZSB0aGUgYmFzZWxpbmUgdmFyaWFibGVzIGFzIHdlbGwuCgpMZXQncyBmaXJzdCBjaGVjayB3aXRoIHRoZSBiYXNlbGluZSBkYXRhIHRvIHNlZSB3aGF0IHZhcmlhYmxlcyB3ZSBtYWRlIHRoZXJlIHNvIEkgY2FuIG1ha2UgdGhlIHNhbWUgb25lcyBmcm9tIHRoZSByb3VuZCAxIGRhdGEuIFRoZXJlIGFyZSBzb21lIHZhcmlhYmxlcyB0aGF0IGFyZSBiYXNlbGluZSB2YXJpYWJsZXMgb25seSBsaWtlIHZhcmlhYmxlcyBhc2tpbmcgYWJvdXQgaGlzdG9yaWNhbCBwcmFjdGljZXMuIFRoZXJlIGFyZSB0aGVuIG90aGVyIHZhcmlhYmxlcyB0aGF0IHdpbGwgdmFyeSBieSBzZWFzb24uIFRoZXNlIGFyZSB0aGUgdmFyaWFibGVzIHRoYXQgd2UgdWx0aW1hdGVseSB3YW50IGluIHRvIHNoYXBlIGluIGEgbG9uZyBkYXRhc2V0IGJ5IHNlYXNvbiB0byBhbmFseXplIGNoYW5nZXMgb3ZlcnRpbWUgaW4gcHJhY3RpY2VzIGFuZCBzb2lsIG1hbmFnZW1lbnQuIEkgdGhpbmsgdGhpcyB3aWxsIHJlc3VsdCBpbiBhIGRhdGFzZXQgdGhhdCBoYXMgb25lIHJvdyBwZXIgZmFybWVyIHBlciBzZWFzb24uIFNvbWUgdmFyaWFibGVzIG1heSBub3QgZml0IG5pY2VseSBpbnRvIHRoaXMgYnV0IHdlIGNhbiBkZWFsIHdpdGggdGhvc2UuIEZvciB2YXJpYWJsZXMgdGhhdCBhcmVuJ3QgY2hhbmdpbmcgb3ZlciB0aW1lIHRoZXknbGwgc2hvdyBhcyBub3QgaW1wb3J0YW50IGluIG91ciBtb2RlbC4gVGhleSdyZSBpbXBvcnRhbnQgZm9yIG1hdGNoaW5nIGZhcm1lcnMuCgpUaGVyZSBhcmUgYSBsb3Qgb2YgdmFyaWFibGVzIHRvIHRyeSB0byBsaW5lIHVwLiBTb21lIGFscmVhZHkgaGF2ZSB0aGUgc2FtZSBuYW1lIGJ1dCBob3cgdG8gYmVzdCBjb21iaW5lIHRoZSBvbmVzIHRoYXQgaGF2ZSBkaWZmZXJlbnQgdmFyaWFibGUgbmFtZXM/IEknbSBnb2luZyB0byB3cml0ZSBhIGZ1bmN0aW9uIHRoYXQgdGFrZXMgYSB2YXJpYWJsZSBuYW1lIGZyb20gYGJgIGFuZCBhIHZhcmlhYmxlIG5hbWUgZnJvbSBgcmAgdGhhdCBzaG91bGQgZ28gdG9nZXRoZXIsIHVwZGF0ZXMgdGhlIGByYCB2YXJpYWJsZSBuYW1lIGFuZCB1c2VzIHRoYXQgaW5mbyB0byBgcmJpbmRgIHRoZSBkYXRhIGludG8gYSBsb25nIGRhdGFzZXQuCgpgYGB7cn0KIyBuYW1lcyhiKQojIG5hbWVzKHIpCgojIGNoZWNrIHRoZSBuYW1lcyB0aGF0IGFscmVhZHkgbWF0Y2gKYmFzZWxpbmVGb3VuZCA8LSBuYW1lcyhiKVtuYW1lcyhiKSAlaW4lIG5hbWVzKHIpXSAjIG5vdCBtYW55IHZhcmlhYmxlIG5hbWVzIGFyZSBhbGlnbmVkCmBgYAoKVXBkYXRlIHZhcmlhYmxlIG5hbWVzIHNvIHRoYXQgYW55IHZhcmlhYmxlIHdpdGggMTZhIG9yIDE2YiBoYXMgYSB0aGUgYGFgIG9yIGBiYCBzZWFzb24gZGVzaWduYXRpb24gYXQgdGhlIGVuZCBpdCBzbyBJIGNhbiByZXBsaWNhdGUgdGhlIGBnYXRoZXIoKWAgYW5kIGBzcHJlYWQoKWAgb3B0aW9ucyBmb3IgcmVvcmdhbml6aW5nIHRoZSBkYXRhIGJ5IHNlYXNvbiBhbmQgYnkgcGxvdC4gVGhpcyBtZWFucyB0aGF0IHRoZSB2YXJpYWJsZSBuYW1lcyB3aWxsIHJldGFpbiB0aGVpciBkZXNpZ25hdGlvbiBvZiBmaXJzdCBvciBzZWNvbmQgYXBwbGljYXRpb24gYW5kIGJlIGRpc3Rpbmd1aXNoYWJsZS4KClRPRE8obWF0dGxvd2VzKSAtIHJlbmFtZSB0aGUgdmFyaWFibGVzIGFjY29yZGluZyB0byB0aGF0IGNvbnZlbnRpb24gdG8gcmVzaGFwZSB0aGUgYHJgIGRhdGEuIEtlZXAgdGhlIGJhc2VsaW5lIGRhdGEgaW4gbWluZCBhcyB3ZSdsbCB3YW50IHRvIGRvIHRoZSBzYW1lIHRoaW5nIHdpdGggdGhlIGJhc2VsaW5lIGRhdGEgdG8gbWFrZSB0aGVtIG1hdGNoLgoKYGBge3J9CnIgPC0gciAlPiUgcmVuYW1lKAogIHdoaWNoX2Nyb3BfMV8xNmEgPSB3aGljaF9jcm9wXzE2YV8xLAogIHdoaWNoX21haXplX3NlZWRfMV8xNmEgPSB3aGljaF9tYWl6ZV9zZWVkXzE2YV8xLAogIHdoaWNoX2Nyb3BfMl8xNmEgPSB3aGljaF9jcm9wXzE2YV8yLAogIHdoaWNoX21haXplX3NlZWRfMl8xNmEgPSB3aGljaF9tYWl6ZV9zZWVkXzE2YV8yLAogIGtnX3NlZWRfdmVnXzFfMTZhID0ga2dfc2VlZF92ZWdfMTZhXzEsCiAga2dfc2VlZF8xXzE2YSA9IGtnX3NlZWRfMTZhXzEsCiAga2dfc2VlZF8yXzE2YSA9IGtnX3NlZWRfMTZhXzIsCiAga2dfeWllbGRfMV8xNmEgPSBrZ195aWVsZF8xNmFfMSwKICBrZ195aWVsZF8yXzE2YSA9IGtnX3lpZWxkXzE2YV8yLAogIHlpZWxkX2NvbXBhcmVfMV8xNmEgPSB5aWVsZF9jb21wYXJlXzE2YV8xLAogIHlpZWxkX2NvbXBhcmVfMl8xNmEgPSB5aWVsZF9jb21wYXJlXzE2YV8yLAogIAogIHdoaWNoX2Nyb3BfMV8xNmIgPSB3aGljaF9jcm9wXzE2Yl8xLAogIHdoaWNoX21haXplX3NlZWRfMV8xNmIgPSB3aGljaF9tYWl6ZV9zZWVkXzE2Yl8xLAogIHdoaWNoX2Nyb3BfMl8xNmIgPSB3aGljaF9jcm9wXzE2Yl8yLAogIHdoaWNoX21haXplX3NlZWRfMl8xNmIgPSB3aGljaF9tYWl6ZV9zZWVkXzE2Yl8yLAogICNrZ19zZWVkX3ZlZ18xXzE2YSA9IGtnX3NlZWRfdmVnXzE2YV8xLAogICNrZ19zZWVkX2FuYW5hc18yXzE2YSA9IGtnX3NlZWRfYW5hbmFzXzE2YV8yLAogICNrZ19zZWVkX2h3YWdfMV8xNmEgPSBrZ19zZWVkX2h3YWdfMTZhXzEsCiAga2dfc2VlZF8xXzE2YiA9IGtnX3NlZWRfMTZiXzEsCiAga2dfc2VlZF8yXzE2YiA9IGtnX3NlZWRfMTZiXzIsCiAga2dfeWllbGRfMV8xNmIgPSBrZ195aWVsZF8xNmJfMSwKICBrZ195aWVsZF8yXzE2YiA9IGtnX3lpZWxkXzE2Yl8yLAogIHlpZWxkX2NvbXBhcmVfMV8xNmIgPSB5aWVsZF9jb21wYXJlXzE2Yl8xLAogIHlpZWxkX2NvbXBhcmVfMl8xNmIgPSB5aWVsZF9jb21wYXJlXzE2Yl8yCikKCgoKYVNlYXNvbiA8LSBuYW1lcyhyKVtncmVwKCIoMS5hKSIsIG5hbWVzKHIpKV0KYlNlYXNvbiA8LSBuYW1lcyhyKVtncmVwKCIoMS5iKSIsIG5hbWVzKHIpKV0Kc2Vhc29uYWxWYXJzIDwtIGMoYVNlYXNvbiwgYlNlYXNvbiwgInNhbXBsZV9pZCIpCmZhcm1lclZhcnMgPC0gYyhuYW1lcyhyKVshbmFtZXMocikgJWluJSBzZWFzb25hbFZhcnNdLCAic2FtcGxlX2lkIikKYGBgCgpgYGB7cn0KIyBleGFtcGxlIGRhdGEKIyBkZiA8LSBkYXRhLmZyYW1lKAojICAgaWQgPSAxOjEwLAojICAgdGltZSA9IGFzLkRhdGUoJzIwMDktMDEtMDEnKSArIDA6OSwKIyAgIFEzLjIuMS4gPSBybm9ybSgxMCwgMCwgMSksCiMgICBRMy4yLjIuID0gcm5vcm0oMTAsIDAsIDEpLAojICAgUTMuMi4zLiA9IHJub3JtKDEwLCAwLCAxKSwKIyAgIFEzLjMuMS4gPSBybm9ybSgxMCwgMCwgMSksCiMgICBRMy4zLjIuID0gcm5vcm0oMTAsIDAsIDEpLAojICAgUTMuMy4zLiA9IHJub3JtKDEwLCAwLCAxKQojICkKIyAKIyBkZiAlPiUKIyAgIGdhdGhlcihrZXksIHZhbHVlLCAtaWQsIC10aW1lKSAlPiUKIyAgIGV4dHJhY3Qoa2V5LCBjKCJxdWVzdGlvbiIsICJsb29wX251bWJlciIpLCAiKFEuXFwuLilcXC4oLikiKSAlPiUKIyAgIHNwcmVhZChxdWVzdGlvbiwgdmFsdWUpCmBgYAoKYGBge3J9CgojIGFEYXQgPC0gclssbmFtZXMocikgJWluJSBhU2Vhc29uXSAjIHdvcmtzIGZvciB0aGlzIHRvbyEKIyBhRGF0IDwtIGFEYXRbLGdyZXAoIjE2YV8xIiwgbmFtZXMoYURhdCkpXSAjIHdvcmtzIGZvciB0aGlzCmFEYXQgPC0gclssbmFtZXMocikgJWluJSBzZWFzb25hbFZhcnNdICMgd29ya3MgZm9yIHRoaXMhCgojaHR0cDovL3N0YWNrb3ZlcmZsb3cuY29tL3F1ZXN0aW9ucy8yNTkyNTU1Ni9nYXRoZXItbXVsdGlwbGUtc2V0cy1vZi1jb2x1bW5zCnNlYXNvbmFsRGF0IDwtIGFEYXQgJT4lCiAgZ2F0aGVyKGtleSwgdmFsdWUsIC1zYW1wbGVfaWQpICU+JQogIHRpZHlyOjpleHRyYWN0KGtleSwgYygidmFyaWFibGUiLCAic2Vhc29uIiksICIoXi4qXFxfMS4pKC4pIikgJT4lCiAgbXV0YXRlKHNlYXNvbiA9IHBhc3RlMCgiMTYiLCBzZWFzb24pKSAlPiUgCiAgc3ByZWFkKHZhcmlhYmxlLCB2YWx1ZSkKCm5hbWVzKHNlYXNvbmFsRGF0KSA8LSBnc3ViKCJfMTYiLCAiIiwgbmFtZXMoc2Vhc29uYWxEYXQpKQoKYGBgCgpUT0RPKG1hdHRsb3dlcykgLSBjb25maXJtIHRoYXQgdGhlIHRpZHlyIHByb2Nlc3Mgd29ya2VkIGFzIEkgZXhwZWN0ZWQgYXMgdGhlcmUgYXJlIG51bWVyb3VzIG1pc3NpbmcgdmFsdWVzLiBUaGVzZSBzZWVtIHRvIGFwcGVhciB3aGVyZSB0aGUgdmFyaWFibGUgb25seSBoYWQgb25lIHZlcnNpb24gb2YgdGhlIHZhcmlhYmxlLCBfMTYsIHJhdGhlciB0aGFuIGEgXzE2YSBhbmQgYSBfMTZiLiBDaGVjayBvdXQgaG93IHRoaXMgaXMgaGFuZGxpbmcgdmFyaWFibGVzIHdpdGggXzE3IGluc3RlYWQgb2YgXzE2LgoKIyMgTWVyZ2Ugc2Vhc29uYWwgYW5kIGRlbW9ncmFwaGljIGRhdGEKCmBgYHtyfQpycyA8LSBsZWZ0X2pvaW4oc2Vhc29uYWxEYXQsIHJbLGMobmFtZXMocilbIW5hbWVzKHIpICVpbiUgc2Vhc29uYWxWYXJzXSwic2FtcGxlX2lkIildLCBieT0ic2FtcGxlX2lkIikKYGBgCgojIyBDb21iaW5lIGxvbmcgd2l0aCBiYXNlbGluZQoKVGhlIGBtYXRjaFJvdW5kc2AgZnVuY3Rpb24gdXBkYXRlcyB2YXJpYWJsZSBuYW1lcyBhY3Jvc3Mgcm91bmRzIGFuZCByZXBvcnRzIHRoZSBpbmRleCBhbmQgbmV3IG5hbWUgb2YgdGhlIHZhcmlhYmxlcy4gSSBjYW4gdGhlbiB0YWtlIHRoZSBmaXJzdCBwYXJ0IG9mIHRoZSBsaXN0IGZvciBgZGF0MWAgYW5kIHRoZSBzZWNvbmQgcGFydCBmb3IgYGRhdDJgLgoKT3IganVzdCBjaGFuZ2UgYmFzZWxpbmUgdmFyaWFibGUgbmFtZXMgbWFudWFsbHkuIFdoYXQncyB0aGUgYmVzdCB3YXkgdG8gZG8gdGhpcz8gRmlyc3QgcmVzaGFwZSB0aGUgYmFzZWxpbmUgdmFyaWFibGVzIHRvIGJlIHBsb3QgbGV2ZWwgYXMgd2VsbCB3aXRoIGEgc2Vhc29uIGluZGljYXRvci4gCgpUT0RPKG1hdHQubG93ZXMpIENvbmZpcm0gdGhhdCB0aGlzIGlzIG5lY2Vzc2FyeS4gSWYgdGhlIGJhc2VsaW5lIGRhdGEgb25seSBpbmNsdWRlcyB0aGUgcHJldmlvdXMgc2Vhc29uIGFuZCB0aGUgaGlzdG9yeSB0aGVuIHRoZSByZXNoYXBlIG1heSBub3QgYmUgbmVjZXNzYXJ5LiBBbGwgc3Vic2VxdWVudCBzdXJ2ZXlzIGFza2VkIGFib3V0IHR3byBzZWFzb25zLCB0aGUgaW50ZXJ2ZW5pbmcgc2Vhc29uIGFuZCB0aGUgcmVsZXZhbnQgc2Vhc29uLiBHZXQgeW91ciBoZWFkIGFyb3VuZCB0aGUgYmFzZWxpbmUgZGF0YSBhZ2FpbiBhbmQgYWN0LgoKYGBge3J9CiMgYiA8LSBiICU+JSByZW5hbWUoCiMgICBpbnB1dHVzZV9wcmlvcmRfZmVydGlsaXplcl8xNWIgPSBpbnB1dHVzZV8xNWJfcHJpb3JkX2ZlcnRpbGl6ZXIsCiMgICBpbnB1dHVzZV9wcmlvcmN1bHR1cmVfMTViXzEgPSBpbnB1dHVzZV8xNWJfcHJpb3JjdWx0dXJlXzE1Yl8xLAojICAgaW5wdXR1c2VfcHJpb3JkX2ludGVyY3JvcF8xNWIgPSBpbnB1dHVzZV8xNWJfcHJpb3JkX2ludGVyY3JvcF8xNWIsCiMgICBpbnB1dHVzZV9wcmlvcmN1bHR1cmVfaW5fMTViID0gaW5wdXR1c2VfMTViX3ByaW9yY3VsdHVyZV8xNWJfaW4sCiMgICBjcm9wMV9zZWV0eV8xNWIgPSBjcm9wMV8xNWJfc2VlZHR5LAojICAgI3Y1OAojICAgY3JvcDFfeWllbGRfMTViID0gY3JvcDFfMTViX3lpZWxkLAojICAgY3JvcDFfeWllbGRfXzE1YiA9IGNyb3AxXzE1Yl95aWVsZF8sCiMgICBjcm9wMl9zZWVkdHlfMTViID0gY3JvcDJfMTViX3NlZWR0eSwKIyAgICM2MwojICAgY3JvcDJfc2VlZGtnXzE1YiA9IGNyb3AyXzE1Yl9zZWVka2csCiMgICBjcm9wMl95aWVsZF8xNmIgPSBjcm9wMl8xNWJfeWllbGQsCiMgICBjcm9wMl95aWVsZF9fMTViID0gY3JvcDJfMTViX3lpZWxkXywKIyAgIGZpZWxkX2ZlcnRfdF8xNWIgPSBmaWVsZF8xNWJfZmVydF90LAojICAgI3Y2OQojICAgZmllbGRfY29tcG9zdF9xdV8xNWIgPSBmaWVsZF9jb21wb3N0X3F1CiMgKQoKYGBgCgpJIHRoaW5rIHRoYXQgYWxsIG5lZWRzIHRvIGJlIGRvbmUgaXMgdG8gYWRkIGEgc2Vhc29uIHZhcmlhYmxlIGFuZCByZW5hbWUgdGhlIGJhc2VsaW5lIHZhcmlhYmxlcyB0byB0YWtlIG9mZiB0aGUgYF8xNWJgIHBvcnRpb24uCgpgYGB7cn0Kd3JpdGUuY3N2KG5hbWVzKGIpLCAiYmFzZWxpbmVWYXJzLmNzdiIsIHJvdy5uYW1lcyA9IFQpCndyaXRlLmNzdihuYW1lcyhycyksICJyb3VuZDFWYXJzLmNzdiIsIHJvdy5uYW1lcyA9IFQpCgpuYW1lcyhiKSA8LSBnc3ViKCJfMTViIiwgIiIsIG5hbWVzKGIpKQpiJHNlYXNvbiA8LSAiMTViIgoKYiA8LSBiICU+JSByZW5hbWUoCiAgICAgIGNyb3AxX2xvY2FsID0gdjU4LAogICAgICBjcm9wMl9sb2NhbCA9IHY2MywKICAgICAgZmllbGRfZmVydF90XzEgPSBmaWVsZF9mZXJ0X3QsCiAgICAgIGZpZWxkX2ZlcnRfdF8yID0gdjY5CiAgICApCmBgYAoKClRPRE8gLSBpdCBhbHNvIHNlZW1zIHRvIHRoZSBjYXNlIHRoYXQgc29tZSBvZiB0aGUgc2VlZCB0eXBlIHZhcmlhYmxlcyBhcmUgbWl4ZWQgdXAgaW4gYHJgIGFuZCBgcnNgLiBTZWUgd2hhdCB0aGUgaXNzdWUgaXMuIEVhY2ggcGxvdCBzaG91bGQgaGF2ZSBvbmx5IG9uZSBhbnN3ZXIgZm9yIHRob3NlLgoKTUFKT1IgVE9ETzogY29uZmlybSB0aGF0IEknbSBub3QgZHVwbGljYXRpbmcgdGhlIHNvaWwgZGF0YSBieSBhc3NpZ25pbmcgaXQgdG8gYm90aCBvZiB0aGUgc2Vhc29ucyB3ZSBhc2tlZCBhYm91dCBpbiB0aGUgZm9sbG93IHVwIHN1cnZleSAoSSB0aGluayBJIGN1cnJlbnRseSBhbSA2LzE1LzE3KS4gV2Ugd2FudCB0byBhY2NvdW50IGZvciBmaWVsZCBtYW5hZ2VtZW50IGluIHRoZSBpbnRlcnZlbmluZyBzZWFzb24gYnV0ICoqd2UgZG9uJ3Qgd2FudCB0byBhc3N1bWUgdGhlIHNvaWwgb3V0Y29tZSBpcyB0aGUgc2FtZSBmb3IgYm90aCBzZWFzb25zLiBTcGVjaWZpY2FsbHksIHRoaXMgbWVhbnMgdGhlIDE2YSBzZWFzb24qKgoKVE9ETyAtIGFkZCB0aGUgYG9ubHlSMWAgdmFyaWFibGVzIGJhY2sgaW50byB0aGUgZGF0YSBzbyB3ZSBoYXZlIGZpZWxkIHRleHR1cmUuCgoqKk5vdGUqKjogdGhlIGZpbmFsIGxvbmcgZGF0YSBieSBwbG90IHNob3VsZCBoYXZlIG9ubHkgb25lIG9ic2VydmF0aW9uIGZvciBzdGF0aW9uYXJ5IHZhcmlhYmxlcyBsaWtlIHNsb3BlIG9yIGhpc3RvcmljYWwgaW5mb3JtYXRpb24KCmBgYHtyfQojIGknbSB1cGRhdGluZyBiYXNlbGluZSBuYW1lcyB0byBtYXRjaCByb3VuZCAxIG5hbWVzLiAKYlVwZGF0ZSA8LSBiICU+JSAKICBtdXRhdGUoCiAgICBkX2NvbXBvc3QgPSBpZmVsc2UoZmllbGRfa2dfY29tcG9zdCA+IDAsIDEsIDApCiAgKSAlPiUKICByZW5hbWUoCiAgdGFibGV0ID0gZGVtb2dyYXBoaWNpZF90YWJsZXQsCiAgdmlsbGFnZSA9IHVtdWR1Z3VkdSwKICBuX2hvdXNlaG9sZCA9IGhoc2l6ZSwKICBuX3R1YnVyYV9zZWFzb24gPSB0b3RhbC5zZWFzb25zLAogIGZpZWxkX2xlbmd0aCA9IGZpZWxkX2RpbTEsICMgSSdtIGFzc3VtaW5nIGRpbTEgaXMgbGVuZ3RoLiBpdCBtaWdodCBub3QgYmUuIEl0IG1pZ2h0IG5vdCBtYXR0ZXIuCiAgZmllbGRfd2lkdGggPSBmaWVsZF9kaW0yLAogIG5fc3BvdHMgPSBuX3Nwb3RzX2MsCiAga2dfc2VlZF8xID0gY3JvcDFfc2VlZGtnLAogIGtnX3NlZWRfMiA9IGNyb3AyX3NlZWRrZywKICBmZXJ0X2tnMSA9IGZpZWxkX2tnX2ZlcnQxLAogIGZlcnRfa2cyID0gZmllbGRfa2dfZmVydDIsCiAga2dfeWllbGRfMSA9IGNyb3AxX3lpZWxkLAogIGtnX3lpZWxkXzIgPSBjcm9wMl95aWVsZCwKICBrZ19jb21wb3N0ID0gZmllbGRfa2dfY29tcG9zdCwKICBkX2NsaWVudCA9IGNsaWVudCwKICBjZWxsX2ZpZWxkID0gY2VsbHVsZV9maWVsZCwKICBmZXJ0X3R5cGUxID0gZmllbGRfZmVydF90XzEsCiAgZmVydF90eXBlMiA9IGZpZWxkX2ZlcnRfdF8yLAogIFguVG90YWwuTml0cm9nZW4gPSBUb3RhbC5OaXRyb2dlbiwKICBYLlNvZGl1bSA9IFNvZGl1bSwKICBYLk9yZ2FuaWMuQ2FyYm9uID0gT3JnYW5pYy5DYXJib24sCiAgWC5FQy4uU2FsdHMuID0gRUMuLlNhbHRzLiwKICBYLkMuRS5DID0gQy5FLkMsCiAgWC5FeGNoYW5nZWFibGUuQWNpZGl0eSA9IEV4Y2hhbmdlYWJsZS5BY2lkaXR5LAogIFguRXhjaGFuZ2VhYmxlLkFsdW1pbml1bSA9IEV4Y2hhbmdlYWJsZS5BbHVtaW5pdW0sCiAgWC5QaG9zcGhvcnVzLlNvcnB0aW9uLkluZGV4Li5QU0kuID0gQWNpZC5TYXR1cmF0aW9uLCAjIGNoZWNrIHRoYXQgdGhpcyBpcyByaWdodAogIG5fY293cyA9IGJldGFpbF9vd25lZG5faW5rYSwKICBuX2dvYXRzID0gYmV0YWlsX293bmVkbl9paGVuZSwKICBuX2NoaWNrZW5zID0gYmV0YWlsX293bmVkbl9pbmtva28sCiAgbl9waWdzID0gYmV0YWlsX293bmVkbl9pbmd1cnViZSwKICBuX3NoZWVwID0gYmV0YWlsX293bmVkbl9pbnRhbWEsCiAgZGF0ZSA9IGRlbW9ncmFwaGljZGF0ZSwKICBmaWVsZF9zbG9wZSA9IGdlbmVyYWxfZmllbGRfaW5mb2dyYWRlX2hpbGwsCiAgZmllbGRfZXJvc2lvbiA9IGdlbmVyYWxfZmllbGRfaW5mb2FudGllcm9zaW9uX2VmLAogIHR5cGVfY29tcG9zdCA9IGZpZWxkX3R5cGVfY29tcG8sCiAgcXVhbGl0eV9jb21wb3N0ID0gZmllbGRfY29tcG9zdF9xdSwKICBkX3NhbXBsZSA9IHNhbXBsZSwKICBlbnVtX25hbWUgPSBzdXJ2ZXlvciwKICBob3dfdXNlX3Jlc2lkdWVzID0gYWN0aW9uX2Nyb3ByZXNpZAopCgojIGJpb2dyYXBoaWNhbCB2YXJpYWxlcyB0aGF0IGFwcGx5IHRvIGFjdGlvbnMgaW4gdGhlIGJhc2VsaW5lIGJlZm9yZSB0aGUgc3R1ZHkgc3RhcnRlZApiaW9WYXJzIDwtIGJVcGRhdGUgJT4lIGRwbHlyOjpzZWxlY3QoCiAgbl9zZWFzb25fZmVydCwgbm9mZXJ0X3doeSwgbl9zZWFzb25fY29tcG9zdCwgbm9jb21wb3N0X3doeSwgbl9zZWFzb25fbGltZSwgbm9saW1lX3doeSwKICBuX3NlYXNvbl9mYWxsb3csIG5fc2Vhc29uc19sZWdfMSwgbl9zZWFzb25zX2xlZ18yLCBhZXosIGNvbnRhaW5zKCJkX3NlYXNvbl9saXN0ZF8iKSwKICBjb250YWlucygiaW5wdXR1c2VfcHJpb3IiKQopCgpiVmFycyA8LSBuYW1lcyhiVXBkYXRlKVshbmFtZXMoYlVwZGF0ZSkgJWluJSBuYW1lcyhiaW9WYXJzKV0gIyByZW1vdmUgYmlvZ3JhcGhpY2FsIHZhcnMKCiMgb3JnYW5pemF0aW9uYWwgdmFyaWFibGVzIHRvIGJlIGlnbm9yZWQKb3JnVmFycyA8LSBiVXBkYXRlICU+JQogIGRwbHlyOjpzZWxlY3QoCiAgICBmaWVsZGNvbGxlY3Rpb25kYXRlLCBkYXRlY29sbGVjdGVkaW5kaXN0cmljdCwgZGF0ZXNlbnR0b2hxLCBkYXRlcmVjZWl2ZWRhdGhxLAogICAgcHJvY2Vzc2VkYXRocV8sIHBhY2tlZGZvcnNlbmRpbmd0b2tlbnlhXywgZGF0ZWZpbmlzaGVkcHJvY2Vzc2luZwogICkKCmJWYXJzIDwtIGJWYXJzWyFiVmFycyAlaW4lIG5hbWVzKG9yZ1ZhcnMpXQoKIyB2YXJpYWJsZXMgdGhhdCBvbmx5IGFwcGVhciBpbiB0aGUgcm91bmQgMSBkYXRhID4+IGxpa2VseSB3YW50IHRvIGtlZXAgdGhlc2UgYW5kIG1ha2UgdGhlbSBwYXJ0IG9mIHRoZSAic3RhYmxlIiBpZGVudGlmeWluZyBkYXRhCm9ubHlSMSA8LSBycyAlPiUKICBkcGx5cjo6c2VsZWN0KAogICAgZmllbGRfbl9jcm9wcywgY3JvcF9kaXJlY3Rpb24sIGZpZWxkX3RleHR1cmUsIHNhbXBsZV9pZAogICkKCnIxVmFycyA8LSBuYW1lcyhycylbIW5hbWVzKHJzKSAlaW4lIG5hbWVzKG9ubHlSMSldCgojIGNoZWNrIHdoYXQncyBhbHJlYWR5IHRoZSBzYW1lCm1hdGNoTmFtZXMgPC0gcjFWYXJzW3IxVmFycyAlaW4lIGJWYXJzXSAjIHRoZXNlIGFyZSB0aGUgbWF0Y2hlcyB3ZSdyZSBnZXR0aW5nCiMgbWF0Y2hOYW1lcwoKIyBjaGVjayB3aGF0IGlzbid0IGFjY291bnRlZCBmb3Igc29tZWhvdwp1bm1hdGNoZWRCIDwtIGJWYXJzWyFiVmFycyAlaW4lIHIxVmFyc10gIyB1bm1hdGNoZWQgYmFzZWxpbmUgbWludXMgZGVtb2dyYXBoaWMgdmFycwp1bm1hdGNoZWRScyA8LSByMVZhcnNbIXIxVmFycyAlaW4lIGJWYXJzXSAjIHVubWF0Y2hlZCByMQpgYGAKCk1ha2UgdGhlIHNhbXBsZSBpZCBsb3dlciBjYXNlCgpgYGB7cn0KYlVwZGF0ZSRzYW1wbGVfaWQgPC0gdG9sb3dlcihiVXBkYXRlJHNhbXBsZV9pZCkKcnMkc2FtcGxlX2lkIDwtIHRvbG93ZXIocnMkc2FtcGxlX2lkKQpgYGAKCgojIyBNZXJnZSBkZW1vZ3JhcGhpYyB2YXJpYWJsZXMKCiogSWRlbnRpZnkgZGVtb2dyYXBoaWMgYW5kIGhpc3RvcmljYWwgdmFyaWFibGVzIGluIGBiYAoqIElkZW50aWZ5IGFueSBuZXcgZGF0YSBmcm9tIFIxIG5vdCBpbiB0aGUgYmFzZWxpbmUgYW5kIG1lcmdlIHRoZW0gaW4KKiBJJ20gdXNpbmcgYGJVcGRhdGVgIGFzIGl0J3MgdGhlIG1vc3QgdXAgdG8gZGF0ZSBhbmQgc2ltcGxpZmllcyB1cGRhdGluZyB0aGUgc2NyaXB0LgoKYGBge3J9CmJEZW1vIDwtIGJVcGRhdGUgJT4lIAogIGRwbHlyOjpzZWxlY3QoCiAgU1NOLCBkaXN0cmljdCwgY2VsbF9maWVsZCwgdmlsbGFnZSwgc2FtcGxlX2lkLCAgCiAgbl9zZWFzb25fZmVydCwgbm9mZXJ0X3doeSwgbl9zZWFzb25fY29tcG9zdCwgbm9jb21wb3N0X3doeSwgbl9zZWFzb25fbGltZSwgbm9saW1lX3doeSwKICBuX3NlYXNvbl9mYWxsb3csIG5fc2Vhc29uc19sZWdfMSwgbl9zZWFzb25zX2xlZ18yLCBhZXosIGNvbnRhaW5zKCJkX3NlYXNvbl9saXN0ZF8iKSwKICBjb250YWlucygiaW5wdXR1c2VfcHJpb3IiKQopCmBgYAoKIyMgQXBwZW5kIGZpZWxkL3NvaWwgdmFyaWFibGVzCgoqIGByYmluZGAgUjEgZmllbGQgbGV2ZWwgdmFyaWFibGVzIHdpdGggYGJgIGZpZWxkIGxldmVsIHZhcmlhYmxlcyB0byBtYWtlIGEgcGxvdCBsZXZlbCBkYXRhc2V0LiAKKiBTZWxlY3Qgb25seSB0aGUgdmFyaWFibGVzIEkgd2FudCB0byBrZWVwCiogR2VuZXJhdGUgYW55IG5ldyBvdXRjb21lcyB0aGF0IGJyaW5nIHRoZSBkYXRhIGRvd24gdG8gYSBzaW5nbGUgb3V0Y29tZSwgcmF0aGVyIHRoYW4gb25lIGJ5IHBsb3QgKiphbmQgc2Vhc29uKiouCiogSSBjYW4gdGhlbiBtYWtlIGxvbmdpdHVkaW5hbCBvdXRjb21lcyBmcm9tIHRob3NlIGRhdGEgYW5kIG1lcmdlIHRob3NlIGludG8gdGhlIGRlbW9ncmFwaGljIGRhdGEKKiAqKlB1dCBpbiB2YXJpYWJsZSBoZXJlIHRoYXQgbWFya3Mgd2hldGhlciB0aGUgZmFybWVyIHJldGFpbmVkIHRoZWlyIHRyZWF0bWVudCBzdGF0dXMgZnJvbSB0aGUgYmFzZWxpbmUqKgoKYGBge3J9CmNvbW1vblZhcnMgPC0gbmFtZXMocnMpW25hbWVzKHJzKSAlaW4lIG5hbWVzKGJVcGRhdGUpXSAjIHVzaW5nIHJzIGJlY2F1c2UgaSBjaGFuZ2VkIHRoZSBiYXNlbGluZSBuYW1lcyB0byBtYXRjaCB0aGUgcnMgbmFtZXMKCndyaXRlLmNzdihjb21tb25WYXJzLCBmaWxlPSJ2YXJOYW1lc2Zvck0mRS5jc3YiKQoKZmllbGREYXQgPC0gcmJpbmQoYlVwZGF0ZVssY29tbW9uVmFyc10sIHJzWyxjb21tb25WYXJzXSkgIyBjb21iaW5lIGJhc2VsaW5lIGFuZCByb3VuZCAxCgojIGFkZCBiYWNrIGluIHRoZSBvbmx5UjEgdmFyaWFibGVzIHRoYXQgd2Ugd2FudCB0byBoYXZlCgpgYGAKCmBzb2lsRGF0YCBpcyB0aGUgb2JqZWN0IHRoYXQgaGFzIHRoZSBzb2lsIHZhcmlhYmxlcyBmb3Igc29pbCBzcGVjaWZpYyBhbmFseXNlcy4gWW91IGNhbiBnZXQgdG8gZmllbGQgb2JzZXJ2YXRpb25zIHdpdGggc29pbCBvYnNlcnZhdGlvbnMgYnkgZHJvcHBpbmcgdGhlIEEgc2Vhc29uIGRhdGEgcG9pbnRzLgoKYGBge3J9CnNvaWxEYXQgPC0gZmllbGREYXQgJT4lIAogIGRwbHlyOjpzZWxlY3Qob25lX29mKHNvaWxWYXJzKSwgU1NOLCBzZWFzb24sIHNhbXBsZV9pZCwgZF9jbGllbnQpICU+JQogIGZpbHRlcihzZWFzb24hPSIxNmEiKSAjIGRyb3BwaW5nIHRoZSAxNmEgdmFsdWVzIGFzIHRoZXNlIGFyZW4ndCB0cnVlIG1lYXN1cmVtZW50cyBidXQgYSByZXN1bHQgb2YgcmVzaGFwaW5nIHRoZSByb3VuZCAxIGRhdGEuCgpmaWVsZFNvaWxEYXQgPC0gZmllbGREYXQgJT4lCiAgZmlsdGVyKHNlYXNvbiE9IjE2YSIpCmBgYAoKYGZpZWxkRGF0YCBpcyBhbGwgc2Vhc29ucyBpbmNsdWRpbmcgMTZhIGZvciB3aGljaCB3ZSBkb24ndCBoYXZlIHNlcGFyYXRlIHNvaWwgb2JzZXJ2YXRpb25zCmBmaWVsZFNvaWxEYXRgIGlzIG9ubHkgMTViIGFuZCAxNmIgZm9yIHdoaWNoIHdlIGhhdmUgc29pbCBvYnNlcnZhdGlvbnMuCgojIyBDcmVhdGUgbmV3IHZhcmlhYmxlcwoKIyMjIEZpZWxkIHZhcmlhYmxlcwoKSSBvcmlnaW5hbGx5IG1hZGUgdGhlc2UgbmV3IG91dGNvbWVzIGZvciBqdXN0IHRoZSByb3VuZCAxIGRhdGEgYnV0IEkgcmVhbGx5IHdhbnQgdG8gaGF2ZSBjb21tb24gb3V0cHV0cyBmb3IgcGxvdHMgYnkgc2Vhc29ucyB0aGF0IEkgY2FuIHRoZW4gdHVybiBpbnRvIGxvbmdpdHVkaW5hbCBvdXRjb21lcy4gCgpgYGB7cn0KZmllbGRTb2lsRGF0JGRpbSA8LSBmaWVsZFNvaWxEYXQkZmllbGRfbGVuZ3RoICogZmllbGRTb2lsRGF0JGZpZWxkX3dpZHRoCmZpZWxkU29pbERhdCRhcmUgPC0gZmllbGRTb2lsRGF0JGRpbS8xMDAKCgppbnB1dFZhcnMgPC0gbmFtZXMoZmllbGRTb2lsRGF0KVtncmVwKCJmZXJ0X3xxdWFsaXR5X2NvbXBvc3R8dHlwZV9jb21wb3N0fHdoaWNoX2Nyb3B8d2hpY2hfbWFpemUiLCBuYW1lcyhmaWVsZFNvaWxEYXQpKV0KCmZpZWxkU29pbERhdFssaW5wdXRWYXJzXSA8LSBzYXBwbHkoZmllbGRTb2lsRGF0WywgaW5wdXRWYXJzXSwgdG9sb3dlcikKCiMgaW5wdXQgcXVhbml0aXRlcwpmaWVsZFNvaWxEYXQkZmVydF9rZ191cmVhMSA8LSBpZmVsc2UoZmllbGRTb2lsRGF0JGZlcnRfdHlwZTE9PSJ1cmVhIiwgZmllbGRTb2lsRGF0JGZlcnRfa2cxLCBOQSkKZmllbGRTb2lsRGF0JGZlcnRfa2dfdXJlYTIgPC0gaWZlbHNlKGZpZWxkU29pbERhdCRmZXJ0X3R5cGUyPT0idXJlYSIsIGZpZWxkU29pbERhdCRmZXJ0X2tnMiwgTkEpCmZpZWxkU29pbERhdCRmZXJ0X3RvdGFsX3VyZWEgPC0gYXBwbHkoZmllbGRTb2lsRGF0WywgZ3JlcCgiKHVyZWEuKSIsIG5hbWVzKGZpZWxkU29pbERhdCkpXSwgMSwgZnVuY3Rpb24oeCl7CiAgc3VtKGFzLm51bWVyaWMoeCksIG5hLnJtPVQpfSkKCgoKZmllbGRTb2lsRGF0JGZlcnRfa2dfZGFwMSA8LSBpZmVsc2UoZmllbGRTb2lsRGF0JGZlcnRfdHlwZTE9PSJkYXAiLCBmaWVsZFNvaWxEYXQkZmVydF9rZzEsIE5BKQpmaWVsZFNvaWxEYXQkZmVydF9rZ19kYXAyIDwtIGlmZWxzZShmaWVsZFNvaWxEYXQkZmVydF90eXBlMj09ImRhcCIsIGZpZWxkU29pbERhdCRmZXJ0X2tnMiwgTkEpCmZpZWxkU29pbERhdCRmZXJ0X3RvdGFsX2RhcCA8LSBhcHBseShmaWVsZFNvaWxEYXRbLCBncmVwKCIoZGFwLikiLCBuYW1lcyhmaWVsZFNvaWxEYXQpKV0sIDEsIGZ1bmN0aW9uKHgpewogIHN1bShhcy5udW1lcmljKHgpLCBuYS5ybT1UKX0pCgoKCmZpZWxkU29pbERhdCRmZXJ0X2tnXzE3bnBrMSA8LSBpZmVsc2UoZmllbGRTb2lsRGF0JGZlcnRfdHlwZTE9PSJucGstMTciLCBmaWVsZFNvaWxEYXQkZmVydF9rZzEsIE5BKQpmaWVsZFNvaWxEYXQkZmVydF9rZ18xN25wazIgPC0gaWZlbHNlKGZpZWxkU29pbERhdCRmZXJ0X3R5cGUyPT0ibnBrLTE3IiwgZmllbGRTb2lsRGF0JGZlcnRfa2cyLCBOQSkKZmllbGRTb2lsRGF0JGZlcnRfdG90YWxfMTducGsgPC0gYXBwbHkoZmllbGRTb2lsRGF0WywgZ3JlcCgiKDE3bnBrLikiLCBuYW1lcyhmaWVsZFNvaWxEYXQpKV0sIDEsIGZ1bmN0aW9uKHgpewogIHN1bShhcy5udW1lcmljKHgpLCBuYS5ybT1UKX0pCgoKCmZpZWxkU29pbERhdCRmZXJ0X2tnXzIybnBrMSA8LSBpZmVsc2UoZmllbGRTb2lsRGF0JGZlcnRfdHlwZTE9PSJucGstMjIiLCBmaWVsZFNvaWxEYXQkZmVydF9rZzEsIE5BKQpmaWVsZFNvaWxEYXQkZmVydF9rZ18yMm5wazIgPC0gaWZlbHNlKGZpZWxkU29pbERhdCRmZXJ0X3R5cGUyPT0ibnBrLTIyIiwgZmllbGRTb2lsRGF0JGZlcnRfa2cyLCBOQSkKZmllbGRTb2lsRGF0JGZlcnRfdG90YWxfMjJucGsgPC0gYXBwbHkoZmllbGRTb2lsRGF0WywgZ3JlcCgiKDIybnBrLikiLCBuYW1lcyhmaWVsZFNvaWxEYXQpKV0sIDEsIGZ1bmN0aW9uKHgpewogIHN1bShhcy5udW1lcmljKHgpLCBuYS5ybT1UKX0pCgoKCmZpZWxkU29pbERhdCRmZXJ0X2tnXzI1NTVucGsxIDwtIGlmZWxzZShmaWVsZFNvaWxEYXQkZmVydF90eXBlMT09Im5wazI1NTUiLCBmaWVsZFNvaWxEYXQkZmVydF9rZzEsIE5BKQpmaWVsZFNvaWxEYXQkZmVydF9rZ18yNTU1bnBrMiA8LSBpZmVsc2UoZmllbGRTb2lsRGF0JGZlcnRfdHlwZTI9PSJucGsyNTU1IiwgZmllbGRTb2lsRGF0JGZlcnRfa2cyLCBOQSkKZmllbGRTb2lsRGF0JGZlcnRfdG90YWxfMjU1NW5wayA8LSBhcHBseShmaWVsZFNvaWxEYXRbLCBncmVwKCIoMjU1NW5way4pIiwgbmFtZXMoZmllbGRTb2lsRGF0KSldLCAxLCBmdW5jdGlvbih4KXsKICBzdW0oYXMubnVtZXJpYyh4KSwgbmEucm09VCl9KQoKCiNsaW1lCmZpZWxkU29pbERhdCRsaW1lX291dHNpZGUgPC0gaWZlbHNlKGZpZWxkU29pbERhdCRkX2xpbWU9PSJsaW1lX291dHNpZGUiLCBmaWVsZFNvaWxEYXQka2dfbGltZSwgTkEpCmZpZWxkU29pbERhdCRsaW1lX3R1YnVyYSA8LSBpZmVsc2UoZmllbGRTb2lsRGF0JGRfbGltZT09ImxpbWVfdHVidXJhIiwgZmllbGRTb2lsRGF0JGtnX2xpbWUsIE5BKQpmaWVsZFNvaWxEYXQkbGltZV9ib3RoIDwtIGlmZWxzZShmaWVsZFNvaWxEYXQkZF9saW1lPT0iYm90aF90dWJ1cmFfbm9uX3R1YnVyYSIsIGZpZWxkU29pbERhdCRrZ19saW1lLCBOQSkKCmlucHV0VmFycyA8LSBuYW1lcyhmaWVsZFNvaWxEYXQpW2dyZXAoImZpZWxkX2xlbmd0aHxmaWVsZF93aWR0aHxkaW18ZmVydF9rZ198ZmVydF90b3RhbF98bGltZV8iLCBuYW1lcyhmaWVsZFNvaWxEYXQpKV0KCmZpZWxkU29pbERhdFssaW5wdXRWYXJzXSA8LXNhcHBseShmaWVsZFNvaWxEYXRbLGlucHV0VmFyc10sIGFzLm51bWVyaWMpCgoKI3VyZWEKZmllbGRTb2lsRGF0JGZlcnRfa2dhcmVfdXJlYTEgPC0gZmllbGRTb2lsRGF0JGZlcnRfa2dfdXJlYTEvZmllbGRTb2lsRGF0JGFyZQpmaWVsZFNvaWxEYXQkZmVydF9rZ2FyZV91cmVhMiA8LSBmaWVsZFNvaWxEYXQkZmVydF9rZ191cmVhMi9maWVsZFNvaWxEYXQkYXJlCmZpZWxkU29pbERhdCRmZXJ0X2tnYXJlX3VyZWFfdG90YWwgPC0gZmllbGRTb2lsRGF0JGZlcnRfdG90YWxfdXJlYS9maWVsZFNvaWxEYXQkYXJlCgojZGFwCmZpZWxkU29pbERhdCRmZXJ0X2tnYXJlX2RhcDEgPC0gZmllbGRTb2lsRGF0JGZlcnRfa2dfZGFwMS9maWVsZFNvaWxEYXQkYXJlCmZpZWxkU29pbERhdCRmZXJ0X2tnYXJlX2RhcDIgPC0gZmllbGRTb2lsRGF0JGZlcnRfa2dfZGFwMi9maWVsZFNvaWxEYXQkYXJlCmZpZWxkU29pbERhdCRmZXJ0X2tnYXJlX2RhcF90b3RhbCA8LSBmaWVsZFNvaWxEYXQkZmVydF90b3RhbF9kYXAvZmllbGRTb2lsRGF0JGFyZQoKI25wazE3CmZpZWxkU29pbERhdCRmZXJ0X2tnYXJlXzE3bnBrMSA8LSBmaWVsZFNvaWxEYXQkZmVydF9rZ18xN25wazEvZmllbGRTb2lsRGF0JGFyZQpmaWVsZFNvaWxEYXQkZmVydF9rZ2FyZV8xN25wazIgPC0gZmllbGRTb2lsRGF0JGZlcnRfa2dfMTducGsyL2ZpZWxkU29pbERhdCRhcmUKZmllbGRTb2lsRGF0JGZlcnRfa2dhcmVfMTducGtfdG90YWwgPC0gZmllbGRTb2lsRGF0JGZlcnRfdG90YWxfMTducGsvZmllbGRTb2lsRGF0JGFyZQoKI25wazIyCmZpZWxkU29pbERhdCRmZXJ0X2tnYXJlXzIybnBrMSA8LSBmaWVsZFNvaWxEYXQkZmVydF9rZ18yMm5wazEvZmllbGRTb2lsRGF0JGFyZQpmaWVsZFNvaWxEYXQkZmVydF9rZ2FyZV8yMm5wazIgPC0gZmllbGRTb2lsRGF0JGZlcnRfa2dfMjJucGsyL2ZpZWxkU29pbERhdCRhcmUKZmllbGRTb2lsRGF0JGZlcnRfa2dhcmVfMjJucGtfdG90YWwgPC0gZmllbGRTb2lsRGF0JGZlcnRfdG90YWxfMjJucGsvZmllbGRTb2lsRGF0JGFyZQoKIzI1NTUgbnBrCmZpZWxkU29pbERhdCRmZXJ0X2tnYXJlXzI1NTVucGsxIDwtIGZpZWxkU29pbERhdCRmZXJ0X2tnXzI1NTVucGsxL2ZpZWxkU29pbERhdCRhcmUKZmllbGRTb2lsRGF0JGZlcnRfa2dhcmVfMjU1NW5wazIgPC0gZmllbGRTb2lsRGF0JGZlcnRfa2dfMjU1NW5wazIvZmllbGRTb2lsRGF0JGFyZQpmaWVsZFNvaWxEYXQkZmVydF9rZ2FyZV8yNTU1bnBrX3RvdGFsIDwtIGZpZWxkU29pbERhdCRmZXJ0X3RvdGFsXzI1NTVucGsvZmllbGRTb2lsRGF0JGFyZQpgYGAKCiMjIyBWaXN1YWxpemUgZmllbGQgdmFyaWFibGVzCgpgYGB7cn0KZmllbGRJbnB1dFZhcnMgPC0gbmFtZXMoZmllbGRTb2lsRGF0KVtncmVwKCJmaWVsZF9sZW5ndGh8ZmllbGRfd2lkdGh8ZGltfGZlcnRfa2dhcmVfIiwgbmFtZXMoZmllbGRTb2lsRGF0KSldCgoKZm9yKGkgaW4gMTpsZW5ndGgoZmllbGRJbnB1dFZhcnMpKXsKICAgIGJhc2UgPC0gZ2dwbG90KGZpZWxkU29pbERhdCwgYWVzKHg9ZmllbGRTb2lsRGF0WyxmaWVsZElucHV0VmFyc1tpXV0pKSArIGxhYnMoeCA9IGZpZWxkSW5wdXRWYXJzW2ldLCB0aXRsZT1maWVsZElucHV0VmFyc1tpXSkKICAgIHRlbXAxIDwtIGJhc2UgKyBnZW9tX2RlbnNpdHkoKQogICAgdGVtcDIgPC0gYmFzZSArIGdlb21faGlzdG9ncmFtKCkKICAgICN0ZW1wMiA8LSBib3hwbG90KHJbLG51bVZhcnNbaV1dLG1haW49cGFzdGUwKCJWYXJpYWJsZTogIiwgbnVtVmFyc1tpXSkpCiAgICBtdWx0aXBsb3QodGVtcDEsIHRlbXAyLCBjb2xzID0gMikKfQpgYGAKClRPRE86IG1ha2UgY2VydGFpbiBJIGRvIHNvbWUgY2hlY2tpbmcgb2YgdGhlc2UgdmFsdWVzIGFib3ZlIGFuZCBpZiBub3QgYWJvdmUsIGhlcmUuCgpgYGB7cn0KIyBmaWVsZERhdCRzZWFzb25fMTZhIDwtIGlmZWxzZShncmVwbCgiMTZhIiwgZmllbGREYXQkbl90dWJ1cmFfc2Vhc29uKSwgMSwgMCkKIyBmaWVsZERhdCRzZWFzb25fMTZiIDwtIGlmZWxzZShncmVwbCgiMTZiIiwgZmllbGREYXQkbl90dWJ1cmFfc2Vhc29uKSwgMSwgMCkKIyBmaWVsZERhdCRzZWFzb25fMTdhIDwtIGlmZWxzZShncmVwbCgiMTdhIiwgZmllbGREYXQkbl90dWJ1cmFfc2Vhc29uKSwgMSwgMCkKIyBmaWVsZERhdCRub3RDbGllbnQzU2Vhc29ucyA8LSBpZmVsc2UoZ3JlcGwoIm5vdF9hX2NsaWVudCIsIGZpZWxkRGF0JG5fdHVidXJhX3NlYXNvbiksIDEsIDApCmBgYAoKQ2hlY2sgZmllbGQgZGltZW5zaW9uczoKCmBgYHtyfQpnZ3Bsb3QoZmllbGRTb2lsRGF0LCBhZXMoeD1maWVsZF93aWR0aCwgeT1maWVsZF9sZW5ndGgpKSArIAogIGdlb21fcG9pbnQoKSArCiAgbGFicyh0aXRsZT0gIkZpZWxkIGRpbWVuc2lvbnMiLCB4ID0gIldpZHRoIChtKSIsIHk9ICJMZW5ndGggKG0pIikKYGBgCgojIyBNYXAgb2Ygc2FtcGxlcwoKYGBge3J9CmxpYnJhcnkoZGlzbW8pCmlmICghKGV4aXN0cygicndhbmRhIikpKXsKICAjIE9ubHkgbmVlZCB0byBnZW9jb2RlIG9uY2UgcGVyIHNlc3Npb24gbGlicmFyeShkaXNtbykKICByd2FuZGEgPC0gdHJ5KGdlb2NvZGUoIlJ3YW5kYSIpKQogICMgSWYgdGhlIGludGVybmV0IGZhaWxzLCB1c2UgYSBsb2NhbCB2YWx1ZSAKICBpZiAoY2xhc3MocndhbmRhKSA9PSAidHJ5LWVycm9yIikgewogICAgcndhbmRhIDwtICIiCiAgICAjIGFydXNoYSRsb25naXR1ZGUgPC0gMzYuNjgyOTkKICAgICMgYXJ1c2hhJGxhdGl0dWRlIDwtIC0zLjM4NjkyNQogIH0gCn0KYGBgCgpTZWUgW2hlcmVdKGh0dHA6Ly9yc3R1ZGlvLXB1YnMtc3RhdGljLnMzLmFtYXpvbmF3cy5jb20vMjA4OTk4XzM1OTJkM2M2YWM5YTQ3Y2NiZjNhMzk5N2VjMmI2OGVjLmh0bWwpIGZvciBtb3JlIG9uIHVzaW5nIG1hcmtlckNsdXN0ZXJPcHRpb25zIGluIGxlYWZsZXQuCgpJbiB0aGUgbWFwIGJlbG93LCB0aGUgbGFyZ2VyIGdyZWVuIGNpcmNsZXMgYXJlIFR1YnVyYSBmYXJtZXJzIGFuZCB0aGUgc21hbGxlciBibHVlIGNpcmNsZXMgYXJlIGNvbnRyb2wgZmFybWVycy4gKipUaGUgbnVtYmVyIG9mIG9ic2VydmF0aW9ucyB3aWxsIGFwcGVhciBsYXJnZXIgb24gdGhlIG1hcCBiZWNhdXNlIGl0J3MgcGxvdCBsZXZlbCBpbnN0ZWFkIG9mIGZhcm1lciBsZXZlbC4qKgoKYGBge3IgbGVhZmxldCwgZmlnLndpZHRoPTksIGZpZy5oZWlnaHQ9N30KZSA8LSByc1shaXMubmEocnMkbG9uKSxdCnNzIDwtIFNwYXRpYWxQb2ludHNEYXRhRnJhbWUoY29vcmRzID0gZVssIGMoImxvbiIsICJsYXQiKV0sIGRhdGE9ZSkKCnBhbCA8LSBjb2xvck51bWVyaWMoYygibmF2eSIsICJncmVlbiIpLCBkb21haW49dW5pcXVlKHNzJGNsaWVudCkpCm1hcCA8LSBsZWFmbGV0KCkgJT4lIGFkZFRpbGVzKCkgJT4lCiAgc2V0Vmlldyhsbmc9cndhbmRhJGxvbmdpdHVkZSwgbGF0PXJ3YW5kYSRsYXRpdHVkZSwgem9vbT04KSAlPiUKICBhZGRDaXJjbGVNYXJrZXJzKGxuZz1zcyRsb24sIGxhdD1zcyRsYXQsIAogICAgICAgICAgICAgICAgICAgcmFkaXVzPSBpZmVsc2Uoc3MkY2xpZW50PT0xLCAxMCw2KSwKICAgICAgICAgICAgICAgICAgIGNvbG9yID0gcGFsKHNzJGNsaWVudCksCmNsdXN0ZXJPcHRpb25zID0gbWFya2VyQ2x1c3Rlck9wdGlvbnMoZGlzYWJsZUNsdXN0ZXJpbmdBdFpvb209MTMsIHNwaWRlcmZ5T25NYXhab29tPUZBTFNFKSkKCm1hcApgYGAKCiMjIExlc3NvbnMgZm9yIE5hdGhhbmllbAoKSGVyZSBhcmUgdGhlIGtleSBwaWVjZXMgb2YgZmVlZGJhY2sgZm9yIHRoZSBuZXh0IHN1cnZleSByb3VuZDoKCiogVmFyaWFibGUgbmFtaW5nIGNvbnZlbnRpb24gLSBxdWl0ZSBhIGJpdCBvZiB3b3JrIGhhZCB0byBiZSBkb25lIHRvIHdvcmsgd2l0aCB0aGUgZGF0YS4gQW55IHBsb3Qgc3BlY2lmaWMgdmFyaWFibGUgc2hvdWxkIGJlIG5hbWVkIHdpdGggXyh5ZWFyKShzZWFzb24pIGF0IHRoZSBlbmQuIFRoaXMgd2lsbCBtYWtlIGl0IGVhc3kgdG8gcmVzaGFwZSB0aG9zZSB2YXJpYWJsZXMgaW50byBwbG90IGxldmVsIHZhcmlhYmxlcy4KKiBDaGVjayB2YXJpYWJsZXMgLSBzb21lIG9mIHRoZSBpbnB1dCB2YXJpYWJsZXMgYXJlIHF1aXRlIGxhcmdlLiBJcyBpdCBwb3NzaWJsZSB0byBoYXZlIENDIGF1dG9tYXRpY2FsbHkgY2FsY3VsYXRlIHF1YW50aXRpZXMgaW4gYSBwZXIgYXJlIHJhdGUgYW5kIHNpZ25hbCB0aGUgZW51bWVyYXRvciBpZiB0aGUgdmFsdWVzIHNlZW0gaGlnaD8gQmV0dGVyIGZpZWxkIGVzdGltYXRlcyBzaG91bGQgaGVscCB3aXRoIHRoaXMgYnV0IHRoYXQgc29ydCBvZiBjaGVjayB3b3VsZCBiZSBhIGdvb2QgcmVhbGl0eSBjaGVjayBpbiB0aGUgZmllbGQuCiogU29pbCB0ZXh0dXJpbmcgLSBob3cgbG9uZyBkaWQgdGhpcyB0YWtlPyBJIHRoaW5rIHdlIGNhbiBoYXZlIHRoaXMgZG9uZSBpbiB0aGUgbGFiCiogU2VlZCB0eXBlcyAtIG5vdCBtYW55IGZhcm1lcnMgcmVzcG9uZGVkIHRvIHRoZSBzZWVkIHR5cGUgcXVlc3Rpb24uIERvIHdlIGhhdmUgYSByZWFzb24gd2h5IGZyb20gZWl0aGVyIGZhcm1lcnMgb3IgZW51bWVyYXRvcnM/IAoqIE5BcyAtIHNvIG1hbnkgTkFzIGluIHRoZSBkYXRhISBXaHk/CiogVGltaW5nIGZvciB1cGNvbWluZyBzdXJ2ZXkKKiAqKkNvbW1jYXJlKio6IFBsZWFzZSBlbnN1cmUgdGhhdCB0aGUgdmFyaWFibGUgbGFiZWxzIGFyZSBpbiB0aGUgcmlnaHQgbGFuZ3VhZ2UgYm94LiBUaGUgZXhwb3J0IEknbSBnZXR0aW5nIGRpcmVjdGx5IGZyb20gQ29tbWNhcmUgaXMgYSBtaXggb2YgRW5nbGlzaCBhbmQgS2lueWFyd2FuZGEgbmFtZXMuIEkgYXNzdW1lIHRoYXQncyBiZWNhdXNlIHRoZSBsYWJlbHMgd2VyZSBub3QgaW4gdGhlIHJpZ2h0IGJveGVzLgoKCkFuYWx5c2lzIFRPRE86CiogZmVhdHVyZSBjcmVhdGlvbiAoaW4gcHJvY2VzcykKKiBtYXRjaGluZyAodGFsayB0byBNYXlhKQogICsgCiogZm9sbG93aW5nIHByZXZpb3VzIHRlbXBsYXRlIChsb29rIGJhY2spCiAgKyAKCkZvciBuZXh0IHdlZWs6CiogdGFsayB3aXRoIE1heWEgYWJvdXQgbWF0Y2hpbmcgbG9uZ2l0dWRpbmFsbHkKKiBzb2lsIGdyYXBocwoKIyBBbmFseXNpcwoKU2FtZSBhcyB0aGUgYmFzZWxpbmUgYW5hbHlzaXMgYnV0IHdpdGggdHdvIHNlYXNvbnMgb2YgZGF0YQoKVE9ETzogY29uZmlybSB0aGF0IGBkX2NsaWVudGAgaXMgcmVmbGVjdGluZyB0aGUgcmlnaHQgc3RhdHVzIGFzIGEgZmFybWVyIGluIHRoZSBkYXRhLiBJcyBpdCBiYXNlbGluZT8gSXMgaXQgcm91bmQgMT8gSXMgaXQgYSBjb21ibyBvZiB0aGUgdHdvPwoKIyMgRGVtb2dyYXBoaWMgc3VtbWFyeQoKIyMjIElkZW50aWZpZXIgdmFyaWFibGVzCgpDcmVhdGUgYSByZWNvcmQgb2YgaG93IG1hbnkgZmFybWVycyBhcmUgam9pbmluZyBhbmQgbGVhdmluZyBUdWJ1cmEgYmV0d2VlbiB0aGUgYmFzZWxpbmUgYW5kIHRoZSBmaXJzdCBmb2xsb3cgdXAgcm91bmQuCgpVc2luZyBgZmllbGREYXRgIHRvIGhhdmUgMTZhIGNvdW50cwoKYGBge3J9CiN0YWJsZShmaWVsZFNvaWxEYXQkZF9jbGllbnQsIGZpZWxkU29pbERhdCRzZWFzb24pCmZpZWxkRGF0ICU+JSAKICBkcGx5cjo6c2VsZWN0KHNhbXBsZV9pZCwgc2Vhc29uLCBkX2NsaWVudCkgJT4lCiAgZ3JvdXBfYnkoc2FtcGxlX2lkKSAlPiUKICBzcHJlYWQoLiwgc2Vhc29uLCBkX2NsaWVudCkgJT4lCiAgcmVuYW1lKAogICAgY2xpZW50MTViID0gYDE1YmAsCiAgICBjbGllbnQxNmEgPSBgMTZhYCwKICAgIGNsaWVudDE2YiA9IGAxNmJgCiAgKSAlPiUKICBtdXRhdGUoCiAgICBiZWNhbWVDbGllbnQgPSBpZmVsc2UoY2xpZW50MTViPT0wICYgY2xpZW50MTZiPT0xLCAxLCAwKSwKICAgIGJlY2FtZUNvbnRyb2wgPSBpZmVsc2UoY2xpZW50MTViPT0xICYgY2xpZW50MTZiPT0wLCAxLCAwKSwKICAgIHN0YXllZENsaWVudCA9IGlmZWxzZShjbGllbnQxNWI9PTEgJiBjbGllbnQxNmI9PTEsIDEsIDApLAogICAgc3RheWVkQ29udHJvbCA9IGlmZWxzZShjbGllbnQxNWI9PTAgJiBjbGllbnQxNmI9PTAsIDEsIDApCiAgKSAlPiUgCiAgdW5ncm91cCgpICU+JQogIGRwbHlyOjpzdW1tYXJpemVfZWFjaCgKICAgIGZ1bnMobWVhbj0gbWVhbiguLCBuYS5ybT1UKSksIC1jKHNhbXBsZV9pZCwgY2xpZW50MTViLCBjbGllbnQxNmEsIGNsaWVudDE2YikKICApICU+JSAKICBtdXRhdGVfZWFjaCgKICAgIGZ1bnMocGFzdGUwKHJvdW5kKC4sMikqMTAwLCAiJSIpKQogICkgJT4lCiAga2FibGUoY2FwdGlvbj0iTW92ZW1lbnQgaW4gU2FtcGxlIiwgZm9ybWF0PSdtYXJrZG93bicpCgpgYGAKCiMjIyBDbGllbnQgY291bnQKClVzaW5nIGBmaWVsZERhdGAgdG8gaGF2ZSAxNmEgY291bnRzCgpgYGB7cn0KY2xpZW50Q291bnQgPC0gZmllbGREYXQgJT4lIAogIGRwbHlyOjpzZWxlY3Qoc2FtcGxlX2lkLCBzZWFzb24sIGRfY2xpZW50KSAlPiUKICBncm91cF9ieShzYW1wbGVfaWQpICU+JQogIHNwcmVhZCguLCBzZWFzb24sIGRfY2xpZW50KSAlPiUKICByZW5hbWUoCiAgICBjbGllbnQxNWIgPSBgMTViYCwKICAgIGNsaWVudDE2YSA9IGAxNmFgLAogICAgY2xpZW50MTZiID0gYDE2YmAKICApCgoKY2xpZW50Q291bnRUYWIgPC0gY2JpbmQoCiAgYXMuZGF0YS5mcmFtZSh0YWJsZShjbGllbnRDb3VudCRjbGllbnQxNWIpKSwKICBhcy5kYXRhLmZyYW1lKHRhYmxlKGNsaWVudENvdW50JGNsaWVudDE2YikpKQoKY2xpZW50Q291bnRUYWIgPC0gY2xpZW50Q291bnRUYWJbLC0zXQpuYW1lcyhjbGllbnRDb3VudFRhYikgPC0gYygiVHJlYXRtZW50IiwgIkNsaWVudHMgMTViIiwgIkNsaWVudHMgMTZiIikKd3JpdGUuY3N2KGNsaWVudENvdW50VGFiLCBmaWxlPXBhc3RlMCgib3V0cHV0LyIsICJjbGllbnRDb3VudFRhYi5jc3YiKSwgcm93Lm5hbWVzID0gRikKYGBgCgpTdWJzZXQgb2YgZmFybWVycyB0aGF0IGtlcHQgc3RhdHVzIGZvciBzb2lsIHJlZ3Jlc3Npb24gdGFibGUuIApUT0RPIC0gZGVjaWRlIGlmIHRoZSBhbmFseXNlcyB0aGF0IGZvbGxvdyBuZWVkIHRvIGJlIHR1cm5lZCBpbnRvIGZ1bmN0aW9ucyBvciBpZiBpdCdzIHN1ZmZpY2llbnQgdG8gc2V0IHRoZSBzYW1wbGUgaGVyZSBhbmQgdXNlIHRoYXQgc2FtZSBzYW1wbGUgZ29pbmcgZm9yd2FyZC4KCmBgYHtyfQpzYW1lU3RhdHVzVmVjIDwtIHNvaWxEYXQgJT4lCiAgZHBseXI6OnNlbGVjdChzYW1wbGVfaWQsIHNlYXNvbiwgZF9jbGllbnQpICU+JQogIGdyb3VwX2J5KHNhbXBsZV9pZCkgJT4lCiAgc3ByZWFkKC4sIHNlYXNvbiwgZF9jbGllbnQpICU+JQogIGFzLmRhdGEuZnJhbWUoKSAlPiUKICBtdXRhdGUoCiAgICBzYW1lID0gaWZlbHNlKGAxNWJgPT1gMTZiYCwgMSwgMCkKICApICU+JQogIGZpbHRlcihzYW1lPT0xKQoKc2FtZVN0YXR1cyA8LSBzb2lsRGF0W3NvaWxEYXQkc2FtcGxlX2lkICVpbiUgc2FtZVN0YXR1c1ZlYyRzYW1wbGVfaWQsXQpzYW1lU3RhdHVzQ291bnQgPC0gdGFibGUoc2FtZVN0YXR1cyRkX2NsaWVudCkvMgp3cml0ZS5jc3Yoc2FtZVN0YXR1c0NvdW50LCBmaWxlPSJvdXRwdXQvc2FtZVN0YXR1c0NvdW50LmNzdiIpCiNzYW1lU3RhdHVzZnMgPC0gc29pbERhdFtzb2lsRGF0JHNhbXBsZV9pZCAlaW4lIHNhbWVTdGF0dXNWZWMkc2FtcGxlX2lkLF0gIwpgYGAKCiMjIFNvaWwgc3VtbWFyeQoKIyMjIEluaXRpYWwgc29pbCBncmFwaHMKClRoZXNlIGdyYXBocyBhcmUgYSBwZWVrIGF0IGhvdyBzb2lsIHBhcmFtZXRlciBhdmVyYWdlcyBhbmQgZGlmZmVyZW5jZXMgbG9vayBiZXR3ZWVuIHRyZWF0bWVudCBhbmQgY29udHJvbCBmYXJtZXJzIHVzaW5nIGJvdGggYmFzZWxpbmUgYW5kIHJvdW5kIDEgdmFsdWVzLiAqKlRoaXMgaXMgYSBwcmVsaW1pbmFyeSByb3VnaCBsb29rKiouIE5leHQgc3RlcHMgaW5jbHVkZToKCiogQ29uZmlybWluZyBjbGllbnQgYXNzaWdubWVudCBhbmQgY2xhcmlmeWluZyBzdGF0dXMKKiBBZGRpdGlvbmFsIGNsZWFuaW5nIG9mIHNvaWwgdmFyaWFibGVzCiAgKyByZWNvbmNpbGUgdXNpbmcgSVFSIG9yIFNEIG1ldGhvZCBmb3IgYWRqdXN0aW5nIGRhdGEKKiBNYXRjaGluZyBvZiBjbGllbnRzIHRvIGRlcml2ZSBhIG1vcmUgY2F1c2FsIGxvb2sgYXQgY2xpZW50IGVmZmVjdHMgb24gc29pbCBwYXJhbWV0ZXJzLgoKW0hlbHBmdWwgY29kZSBmb3IgcHV0dGluZyB0aGUgZ3JhcGhpY3MgdG9nZXRoZXJdKGh0dHBzOi8vZ2l0aHViLmNvbS90aWR5dmVyc2UvZ2dwbG90Mi93aWtpL01peGluZy1nZ3Bsb3QyLWdyYXBocy13aXRoLW90aGVyLWdyYXBoaWNhbC1vdXRwdXQpCgojIyMgU29pbCBtZWFucyBhbmQgZGlmZnMKClRPRE86IENsZWFuIHNvaWwgZGF0YSBoZXJlIG9uY2UgU3RlcCBhbmQgUGF0cmljayBoYXZlIHNvbWUgZmVlZGJhY2sgcmVnYXJkaW5nIHdoYXQgYXJlIHJlYXNvbmFibGUgYW5kIHVucmVhc29uYWJsZSB2YWx1ZXMuCgpgc29pbE91dGAgaGFzIGNvbW1vbiBtb2RpZmljYXRpb25zLiBBbGwgcmVzdWx0aW5nIHNvaWwgb3V0Y29tZXMgYXJlIG1hZGUgdXNpbmcgdGhhdC4gU29pbCBvdXRjb21lcyBhcmUgbmFtZWQgYHNvaWxPdXQub3V0Y29tZV9uYW1lYC4gVGhpcyB1c2VzIG9ubHkgZmFybWVycyB0aGF0IGhhdmUgdGhlIHNhbWUgdHJlYXRtZW50IHN0YXR1cyBpbiAxNWIgYW5kIDE2YgoKYGBge3J9CnNvaWxPdXQgPC0gc29pbERhdCAlPiUgCiAgZmlsdGVyKHNvaWxEYXQkc2FtcGxlX2lkICVpbiUgc2FtZVN0YXR1c1ZlYyRzYW1wbGVfaWQpICU+JQogIG11dGF0ZSgKICBtZWFzdXJlID0gaWZlbHNlKHNlYXNvbj09IjE1YiIsIDEsIAogICAgICAgICAgICAgICAgICAgaWZlbHNlKHNlYXNvbj09IjE2YiIsIDIsTkEpKQopICU+JSBhcnJhbmdlKG1lYXN1cmUpICU+JQogIGFzLmRhdGEuZnJhbWUoKQoKc29pbE91dC5NZWFuIDwtIHNvaWxPdXQgJT4lCiAgZ3JvdXBfYnkoc2FtcGxlX2lkKSAlPiUKICBzdW1tYXJpemVfZWFjaCgKICAgIGZ1bnMobWVhbiguLCBuYS5ybT1UKSksIC1jKFNTTiwgc2Vhc29uLCBtZWFzdXJlLCBkX2NsaWVudCkKICApICU+JSAKICB1bmdyb3VwKCkgJT4lIAogIGFzLmRhdGEuZnJhbWUoKSAlPiUKICByZW5hbWVfKC5kb3RzID0gc2V0TmFtZXMobmFtZXMoLiksIGdzdWIoIlhcXC58XFwuIiwgIiIsIG5hbWVzKC4pKSkpCgojIGZpbmQgYSB3YXkgdG8gZml0IHRoaXMgaW50byBwaXBpbmcKbmFtZXMoc29pbE91dC5NZWFuKVsyOjE5XSA8LSBwYXN0ZTAobmFtZXMoc29pbE91dC5NZWFuKVsyOjE5XSwgIi5tZWFuIikKCiMgMHMgYXJlIHdoZW4gd2UgaGF2ZSBvbmx5IG9uZSBvYnNlcnZhdGlvbgpzb2lsT3V0LkRpZmYgPC0gc29pbE91dCAlPiUKICBncm91cF9ieShzYW1wbGVfaWQpICU+JQogICMgc3VtbWFyaXNlX2VhY2goCiAgIyAgIGZ1bnMoaWZfZWxzZShsZW5ndGgoLik9PTIsIGRpZmYoeCksIC4pKSwgLWMoU1NOLCBzZWFzb24sIHNhbXBsZV9pZCwgbWVhc3VyZSkKICAjICkgJT4lIHVuZ3JvdXAoKSAlPiUgYXMuZGF0YS5mcmFtZSgpCiAgbXV0YXRlX2VhY2goCiAgICBmdW5zKC4gLSBsYWcoLiwgZGVmYXVsdD1maXJzdCguKSkpLCAtYyhTU04sIHNlYXNvbiwgbWVhc3VyZSwgZF9jbGllbnQpCiAgKSAlPiUKICBmaWx0ZXIobWVhc3VyZT09MikgJT4lCiAgYXMuZGF0YS5mcmFtZSgpICU+JQogIHJlbmFtZV8oLmRvdHMgPSBzZXROYW1lcyhuYW1lcyguKSwgZ3N1YigiWFxcLnxcXC4iLCAiIiwgbmFtZXMoLikpKSkKCiMgZmluZCBhIHdheSB0byBmaXQgdGhpcyBpbnRvIHBpcGluZwpuYW1lcyhzb2lsT3V0LkRpZmYpWzE6MThdIDwtIHBhc3RlMChuYW1lcyhzb2lsT3V0LkRpZmYpWzE6MThdLCAiLmRpZmYiKQoKCiMgZ2F0aGVyIHNvaWwgb3V0Y29tZXMgdG8gbWVyZ2UgYmFjayB0b2dldGhlcgojc29pbFRyYW5zIDwtIGxpc3QobHMoKVtncmVwKCJzb2lsT3V0LiIsIGxzKCkpXSkKCnNvaWxNZXJnZSA8LSBtZXJnZShzb2lsT3V0Lk1lYW4sIHNvaWxPdXQuRGlmZixieT0ic2FtcGxlX2lkIikKCgpsaWJyYXJ5KHRpZHlyKQpsaWJyYXJ5KFJHcmFwaGljcykKc29pbEdyYXBoIDwtIHNvaWxNZXJnZSAlPiUKICBnYXRoZXIodmFyaWFibGUsIHZhbHVlLCAtYyhTU04sIHNhbXBsZV9pZCwgbWVhc3VyZSwgc2Vhc29uLCBkX2NsaWVudCkpICU+JQogIHNlcGFyYXRlKHZhcmlhYmxlLCBjKCJzb2lsQ2hhciIsICJ0eXBlIiksIHNlcD0iXFwuIikKCmZvcihpIGluIDE6bGVuZ3RoKHVuaXF1ZShzb2lsR3JhcGgkc29pbENoYXIpKSl7CiAgZm9yKGogaW4gMTpsZW5ndGgodW5pcXVlKHNvaWxHcmFwaCR0eXBlKSkpewogICAgCiAgICB0ZW1wIDwtIHNvaWxHcmFwaCAlPiUgCiAgICAgIGZpbHRlcihzb2lsQ2hhcj09dW5pcXVlKHNvaWxHcmFwaCRzb2lsQ2hhcilbaV0gJiBzb2lsR3JhcGgkdHlwZT09dW5pcXVlKHNvaWxHcmFwaCR0eXBlKVtqXSkgJT4lCiAgICAgIG11dGF0ZSgKICAgICAgICB2YWx1ZSA9IGlmZWxzZShpcy5pbmZpbml0ZSh2YWx1ZSksIE5BLCB2YWx1ZSkKICAgICAgKQogICAgCiAgICAKICAgICBncGggPSBnZ3Bsb3QodGVtcCwgYWVzKHggPSBkX2NsaWVudCwgeT12YWx1ZSkpICsgCiAgICAgICBnZW9tX2JveHBsb3QoKSArIAogICAgICAgbGFicyh0aXRsZSA9IHBhc3RlKCJOT04tTUFUQ0hFRCBQUkVMSU0gLSIsIHVuaXF1ZShzb2lsR3JhcGgkc29pbENoYXIpW2ldLCB1bmlxdWUoc29pbEdyYXBoJHR5cGUpW2pdLCBzZXA9IiAiKSwgeCA9ICJUcmVhdG1lbnQgdi4gQ29udHJvbCIsIHk9dW5pcXVlKHNvaWxHcmFwaCRzb2lsQ2hhcilbaV0pCiAgICAKICAgIAogICAgCiAgICAgIHRhYiA9IHRhYmxlR3JvYigKICAgICAgICBhZ2dyZWdhdGUodGVtcCR2YWx1ZSwgYnk9bGlzdCh0ZW1wJGRfY2xpZW50KSwgZnVuY3Rpb24oeCl7CiAgICAgICAgcGFzdGUocm91bmQobWVhbih4LCBuYS5ybT1UKSwyKSwgIiAoIiwgcm91bmQoc2QoeCxuYS5ybT1UKSwyKSwgIikiLCBzZXA9IiIpCiAgICAgICAgICB9KSwKICAgICAgICBjb2xzID0gYygiVHJlYXRtZW50IiwgIk1lYW4gKHNkKSIpKQogICAgICAKCiAgICAgIGdyaWQuYXJyYW5nZShncGgsIHRhYiwgbmNvbD0yLCB0b3A9cGFzdGUoIk5PTi1NQVRDSEVEIFBSRUxJTSAtIiwgdW5pcXVlKHRlbXAkc29pbENoYXIpLCB1bmlxdWUodGVtcCR0eXBlKSwgc2VwPSIgIikpCgogIH0KfQoKCmBgYAoKIyMjIFNvaWwgc3VtbWFyeSB0YWJsZQoKKipOb3RlKio6IFRoaXMgdGFibGUgaXMgcHJlbGltaW5hcnkgYW5kIGRvZXMgbm90IHJlZmxlY3QgdmFsdWVzIHJlYWR5IGZvciBpbnRlcnByZXRhdGlvbiAoNi8xOSkuIFRoaXMgdXNlcyAqKmFsbCBmYXJtZXJzKiouCgpgYGB7cn0KdGFiT3V0IDwtIGRvLmNhbGwocmJpbmQsIGxhcHBseShzcGxpdChzb2lsR3JhcGgsIGxpc3Qoc29pbEdyYXBoJHR5cGUsIHNvaWxHcmFwaCRzb2lsQ2hhcikpLCBmdW5jdGlvbih4KXsKICAKICB4IDwtIHggJT4lIG11dGF0ZSgKICAgdmFsdWUgPSBpZmVsc2UoaXMuaW5maW5pdGUodmFsdWUpLCBOQSwgdmFsdWUpIAogICkKICAKICB0ZW1wID0gYWdncmVnYXRlKHgkdmFsdWUsIGJ5PWxpc3QoeCRkX2NsaWVudCksIEZVTj1tZWFuLCBuYS5ybT1UKQogIHB2YWwgPSByb3VuZCh3aWxjb3gudGVzdCh2YWx1ZSB+IGRfY2xpZW50LCBkYXRhPXgpJHAudmFsdWUsMykKICBUbWVhbiA9IHJvdW5kKHRlbXAkeFsyXSwgMikKICBDbWVhbiA9IHJvdW5kKHRlbXAkeFsxXSwgMikKICAKICBvdXRwdXQgPSBkYXRhLmZyYW1lKGNhdCA9IHBhc3RlMCh1bmlxdWUoeCRzb2lsQ2hhciksICIgLSAiLCB1bmlxdWUoeCR0eXBlKSksIENtZWFuLCBUbWVhbiwgcHZhbCkKICByZXR1cm4ob3V0cHV0KQogIAp9KSkKCnRhYk91dCA8LSB0YWJPdXQgJT4lIAogIG11dGF0ZShwdmFsLmFkaiA9IHJvdW5kKHAuYWRqdXN0KHB2YWwsICJmZHIiKSwzKSkgJT4lCiAgYXJyYW5nZShwdmFsLmFkaikKCmthYmxlKHRhYk91dCwgZm9ybWF0PSdtYXJrZG93bicsIHJvdy5uYW1lcyA9IEYsIGNvbC5uYW1lcyA9IGMoIk91dGNvbWUiLCAiQ29udHJvbCBtZWFuIiwgIk9BRiBtZWFuIiwgInAtdmFsdWUiLCAiYWRqLiBwLXZhbHVlIikpCmBgYAoKIyMjIExvbmdpdHVkaW5hbCBzb2lsIGdyYXBocwoKYGBge3J9CnNvaWxMaW5lR3JhcGggPC0gc29pbE91dCAlPiUKICBncm91cF9ieShkX2NsaWVudCwgc2Vhc29uKSAlPiUKICBzdW1tYXJpemVfZWFjaCgKICAgIGZ1bnMobWVhbiguLCBuYS5ybT1UKSksIC1jKFNTTiwgc2FtcGxlX2lkKQogICkgJT4lCiAgZ2F0aGVyKHZhcmlhYmxlLCB2YWx1ZSwgLWMoc2Vhc29uLCBkX2NsaWVudCkpICU+JQogIGZpbHRlcih2YXJpYWJsZSAlaW4lIGtleVNvaWxWYXJzKQogIApwZGYoZmlsZT1wYXN0ZSgib3V0cHV0LyIsICJrZXkgc29pbCB2YXJzIC0gbG9uZ2l0dWRpbmFsLnBkZiIsIHNlcCA9ICIiKSwgd2lkdGg9MTEsIGhlaWdodD04LjUpCmZvcihpIGluIDE6bGVuZ3RoKGtleVNvaWxWYXJzKSl7CiAgICBwcmludChnZ3Bsb3Qoc3Vic2V0KHNvaWxMaW5lR3JhcGgsIHNvaWxMaW5lR3JhcGgkdmFyaWFibGU9PWtleVNvaWxWYXJzW2ldKSwgYWVzKHggPSBzZWFzb24sIHkgPSB2YWx1ZSwgZ3JvdXA9ZF9jbGllbnQsIGNvbG9yPWRfY2xpZW50KSkgKyAKICAgICAgZ2VvbV9saW5lKCkgKwogICAgICBsYWJzKHRpdGxlPXBhc3RlKGtleVNvaWxWYXJzW2ldLCAib3ZlciB0aW1lIGJ5IGNsaWVudCBzdGF0dXMgLSBzYW1lIG9ubHkiLCBzZXA9ICIgIiksCiAgICAgICAgICB4PSAiU2Vhc29uIiwgeT1rZXlTb2lsVmFyc1tpXSwgY29sb3I9IlRyZWF0bWVudCIpCiAgICApCiAgbWFrZUZvb3Rub3RlKGZvb3Rub3RlKQogICAgCn0KZGV2Lm9mZigpCmBgYAoKSGVyZSBpcyB0aGUgdGFibGUgaW4gc2VjdGlvbiAxIG9mIHRoZSByZXBvcnQuIAoKYGBge3J9CnNvaWxMaW5lR3JhcGggJT4lCiAgc3ByZWFkKHNlYXNvbiwgdmFsdWUpICU+JQogIGFycmFuZ2UodmFyaWFibGUpICU+JQogIHJlbmFtZSgKICAgIHllYXIxID0gYDE1YmAsCiAgICB5ZWFyMiA9IGAxNmJgCiAgKSAlPiUKICBtdXRhdGVfaWYoCiAgICBpcy5udW1lcmljLCBmdW5zKHJvdW5kKC4sMykpCiAgKSAlPiUgCiAgd3JpdGUuY3N2KC4sIGZpbGU9Im91dHB1dC9zdW1UYWIxLmNzdiIpCgpgYGAKCgojIyMgUmVncmVzc2lvbnMKClNlZSBbc2tldGNoIG9mIFNIUyByZXBvcnRdKGh0dHBzOi8vZG9jcy5nb29nbGUuY29tL2RvY3VtZW50L2QvMWtvTnNLeng5N18zcnBrR2VKSTZQblBkWU5NZFY5cTRlLWNQUXhBV0RlRGsvZWRpdCkuICBSZW1lbWJlciB0aGF0IGBzYW1lU3RhdHVzYCBhcmUgdGhlIGZhcm1lcnMgdGhhdCBrZXB0IHRoZWlyIHN0YXR1cyBiZXR3ZWVuIGJhc2VsaW5lIGFuZCBlbmRsaW5lLiBUaGUgdHdvIG1vZGVscyBvZiBpbnRlcmVzdCBhcmU6CgoqIEluZGl2aWR1YWwgZml4ZWQgZWZmZWN0cyBhY2NvdW50IGZvciB0aGluZ3Mgc3BlY2ljaWMgdG8gZmFybWVyIHRoYXQgZG9uJ3QgY2hhbmdlIG92ZXIgdGltZQoqIGNhbiBjb250cm9sIGZvciB1bm9ic2VydmVkIHNvdXJjZXMgb2YgaGV0ZXJvZ2VuZWl0eSBvdmVyIHRpbWUsIHZlcnkgc2Vuc2l0aXZlIHRvIG1vZGVsIAoqIGFkZCBpbiBvdGhlciBkYXRhIHBvaW50cyB0aGF0IGRvIGNoYW5nZSBvdmVyIHRpbWUKKiBzbyBhZGQgaW4gdGhpbmdzIHRoYXQgY2hhbmdlIG92ZXIgdGltZSB0aGF0IHBsYXVzaWJseSBhZmZlY3Qgb3VyIG91dGNvbWUKKiBmZXJ0aWxpemVyIGFuZCBzZWVkIHVzZSBhcmUgc3lub3ltb3VzIHdpdGggYmVpbmcgYSBjbGllbnQgb3Igbm90LCBoaWdobHkgZW5kb2dlbm91cwoqIHJ1biB0d28gcmVncwogKyBvbmUgd2l0aCBvYWYgCiArIG9uZSB3aXRoIG9hZiBhbmQgZmVydGlsaXplcgoqIHRoaW5ncyBsaWtlIHNsb3BlIGFyZSBjb2xsaW5lYXIKKiBpbmRpdmlkdWFsIGZpeGVkIGVmZmVjdHMgbWFrZXMgbW9yZSBzZW5zZSB0aGFuIHVzaW5nIFBTTSBub3cgdGhhdCB3ZSBoYXZlIG11bHRpcGxlIHllYXJzLgoqIG1lYW5zIGJ5IGRpcmVjdGlvbmFsIGNoYW5nZXMKKiBwYXBlcnMgdXNpbmcgZml4ZWQgZWZmZWN0cyBieSBtaWd1ZWwgb24gd2hldGhlciBjaGFuZ2VzIHRvIHJ1cmFsIHRvIHVyYmFuIGFyZWFzIGFuZCBpbmNvbWUKCgpDb25zaWRlciBpbmNsdWRpbmc6CgoqIHRpbWUgRkVzCiogYWdlIGFuZCBhIHNxdWFyZWQgYWdlIHRlcm0KKiBnZW5kZXIgKGFic29yYmVkIGJ5IGZpeGVkIGVmZmVjdHMpCiogeWVhcnMgb2YgZWR1Y2F0aW9uIChhYnNvcmJlZCBieSBmaXhlZCBlZmZlY3RzKQoqIGJvb3RzdHJhcHBlZCBzdC4gZXJyb3JzIC8gcm9idXN0IHN0YW5kYXJkIGVycm9ycwoKW0hlbHBmdWwgbGlua10oaHR0cHM6Ly93d3cuci1ibG9nZ2Vycy5jb20vaG93LXRvLWdvLXBhcmFsbGVsLWluLXItYmFzaWNzLXRpcHMvKSBmb3IgZXhlY3V0aW5nIGNvZGUgaW4gcGFyYWxsZWwKCmBgYHtyfQpzb3VyY2UoIi4uL29hZmxpYi9wbG0uUiIpCmZpZWxkU29pbERhdCA8LSBmaWVsZFNvaWxEYXQgJT4lCiAgbXV0YXRlKAogICAgYWdlMiA9IGFnZV4yCiAgKQoKCmluZEZlTGlzdCA8LSBsaXN0KCJhcy5mYWN0b3IoZF9jbGllbnQpIiwgCiAgICAgICAgICAgICAgICAgIGMoImFzLmZhY3RvcihkX2NsaWVudCkiLCAiYXMuZmFjdG9yKHNhbXBsZV9pZCkiKSwKICAgICAgICAgICAgICAgICAgYygiYXMuZmFjdG9yKGRfY2xpZW50KSIsICJhcy5mYWN0b3Ioc2FtcGxlX2lkKSIsICJhcy5mYWN0b3Ioc2Vhc29uKSIpLAogICAgICAgICAgICAgICAgICBjKCJhcy5mYWN0b3IoZF9jbGllbnQpIiwgImFzLmZhY3RvcihzYW1wbGVfaWQpIiwgImFzLmZhY3RvcihzZWFzb24pIiwgImFnZSIsICJhZ2UyIikpCgoKZm9yY2VVcGRhdGUgPC0gRkFMU0UKIyBydW4gdGhpcyBpbiBwYXJhbGxlbCB0byBzcGVlZCB1cCB0aGUgcHJvY2VzcwojIGxvYWQgdGhlIGRhdGEgYW5kIHZhcmlhYmxlcyBhbmQgcGFja2FnZXMgaW50byB0aGUgY2x1c3RlcgpyZWdGaWxlIDwtICJyZWdGaWxlLlJEYXRhIgojZm9yY2VVcGRhdGUgPC0gZm9yY2VVcGRhdGVBbGwKaWYoIWZpbGUuZXhpc3RzKHJlZ0ZpbGUpIHx8IGZvcmNlVXBkYXRlKSB7CmxpYnJhcnkocGFyYWxsZWwpCm5vX2NvcmVzIDwtIGRldGVjdENvcmVzKCkgLSAxCgpjbCA8LSBtYWtlQ2x1c3Rlcihub19jb3JlcywgdHlwZT0iRk9SSyIpCmNsdXN0ZXJFdmFsUShjbCwgInBsbSIpCmNsdXN0ZXJFeHBvcnQoY2wsICJmaWVsZFNvaWxEYXQiKQpjbHVzdGVyRXhwb3J0KGNsLCAia2V5U29pbFZhcnMiKQpjbHVzdGVyRXhwb3J0KGNsLCAiaW5kRmVMaXN0IikKCmluZEZlTG9vcCA8LSBwYXJMYXBwbHkoY2wsIGluZEZlTGlzdCwgZnVuY3Rpb24obW9kKXsKICBsYXBwbHkoa2V5U29pbFZhcnMsIGZ1bmN0aW9uKG91dGNvbWUpewogICAgZm9ybSA9IGxtKHJlZm9ybXVsYXRlKHRlcm1sYWJlbHMgPSBtb2QsIHJlc3BvbnNlID0gb3V0Y29tZSksIGRhdGE9ZmllbGRTb2lsRGF0KQogICAgCiAgICBwZGYoZmlsZT1wYXN0ZSgib3V0cHV0LyIsIHBhc3RlMChvdXRjb21lLCBwYXN0ZShtb2QsIGNvbGxhcHNlID0gIiIpKSwgIi5wZGYiLCBzZXAgPSAiIikpIAogICAgcHJpbnQocGxvdChmb3JtKSkKICAgIGRldi5vZmYoKQogICAgCiAgICBmb3JtID0gcGxtKGZvcm0sIGMoInNhbXBsZV9pZCIsICJhZ2UiLCAiYWdlMiIpKQogICAgCiAgICByb3duYW1lcyhmb3JtKSA9IHBhc3RlKHJvd25hbWVzKGZvcm0pLCBvdXRjb21lLCBzZXAgPSAiICIpCiAgICByZXR1cm4oZm9ybSkKICB9KQogIAp9KQpzdG9wQ2x1c3RlcihjbCkKc2F2ZShpbmRGZUxvb3AsIGZpbGU9cmVnRmlsZSkKfSBlbHNlIHsKICBsb2FkKCJyZWdGaWxlLlJEYXRhIikKfQpgYGAKCk5vdGVzOgoKKipCYXNlZCBvbiByZWdyZXNzaW9uIGRpYWdub3N0aWNzIGZvciBlYWNoIG91dGNvbWUsIGhlcmUgYXJlIHRoZSBzdGVwcyBJJ20gdGFraW5nOioqCgoqIENhbGNpdW0gLSBjaGVjayB0aGUgaGVhdnkgdGFpbHMsIG1ha2UgbW9kZWwgcm9idXN0PwoqIE1hZ25lc2l1bSAtIHNhbWUKKiBwSCAtIHNhbWUsIG5vdCB0b28gYmFkIGJ1dCBzb21lIGNvbmNlcm5pbmcgdmFsdWVzCiogQ2FyYm9uIC0gYWN0dWFsbHkgbm90IHRvbyBiYWQgYnV0IGNoZWNrIGhlYXZ5IHRhaWxzCiogTml0cm9nZW4gLSB3ZWlyZC4gQ2hlY2sgZm9yIGhlYXZ5IHRhaWxzCgpMaW5rcyBmb3Igcm9idXN0IHJlZ3Jlc3Npb246CgoqIFtVQ0xBXShodHRwczovL3N0YXRzLmlkcmUudWNsYS5lZHUvci9kYWUvcm9idXN0LXJlZ3Jlc3Npb24vKQoKQ2hlY2sgb3V0IHJvYnVzdGJhc2UgYGxtcm9iYCBmb3Igcm9idXN0IGxtIGFuZCBgcmxtYCBmcm9tIE1BU1MuIE9ubHkgdXNlIHRoZSBmdWxsIG1vZGVsIHNwZWNpZmljYXRpb24uCmBgYHtyLCBldmFsPUZ9CmZvcmNlVXBkYXRlIDwtIEZBTFNFCiMgcnVuIHRoaXMgaW4gcGFyYWxsZWwgdG8gc3BlZWQgdXAgdGhlIHByb2Nlc3MKIyBsb2FkIHRoZSBkYXRhIGFuZCB2YXJpYWJsZXMgYW5kIHBhY2thZ2VzIGludG8gdGhlIGNsdXN0ZXIKcmVnUm9idXN0RmlsZSA8LSAicmVnUm9idXN0RmlsZS5SRGF0YSIKI2ZvcmNlVXBkYXRlIDwtIGZvcmNlVXBkYXRlQWxsCmlmKCFmaWxlLmV4aXN0cyhyZWdSb2J1c3RGaWxlKSB8fCBmb3JjZVVwZGF0ZSkgewpsaWJyYXJ5KHBhcmFsbGVsKQpub19jb3JlcyA8LSBkZXRlY3RDb3JlcygpIC0gMQoKY2wgPC0gbWFrZUNsdXN0ZXIobm9fY29yZXMsIHR5cGU9IkZPUksiKQpjbHVzdGVyRXZhbFEoY2wsICJwbG0iKQpjbHVzdGVyRXhwb3J0KGNsLCAiZmllbGRTb2lsRGF0IikKY2x1c3RlckV4cG9ydChjbCwgImtleVNvaWxWYXJzIikKY2x1c3RlckV4cG9ydChjbCwgImluZEZlTGlzdCIpCgppbmRGZUxvb3AgPC0gcGFyTGFwcGx5KGNsLCBrZXlTb2lsVmFycywgZnVuY3Rpb24ob3V0Y29tZSl7CiAgICAKICAjdGVzdCAgPSBsbXJvYihyZWZvcm11bGF0ZSh0ZXJtbGFiZWxzID0gaW5kRmVMaXN0W1s0XV0sIHJlc3BvbnNlID0gb3V0Y29tZSksIGRhdGE9ZmllbGRTb2lsRGF0KQogIAogICAgIyBhZGRyZXNzIGR1cGxpY2F0ZSBwYWlycyBvZiBYIGFuZCBZID4+IGJ1dCB3aGF0IGlzIG91ciBYIHdoZW4gd2UgaGF2ZSBhbGwgdGhlc2UgZmVhdHVyZXM/CiAgICBmb3JtID0gcmxtKHJlZm9ybXVsYXRlKHRlcm1sYWJlbHMgPSBpbmRGZUxpc3RbWzRdXSwgcmVzcG9uc2UgPSBvdXRjb21lKSwgZGF0YT1maWVsZFNvaWxEYXQpCiAgICAKICAgIHBkZihmaWxlPXBhc3RlKCJvdXRwdXQvcm9idXN0LyIsIHBhc3RlMChvdXRjb21lLCBwYXN0ZShpbmRGZUxpc3RbWzRdXSwgY29sbGFwc2UgPSAiIikpLCAiLnBkZiIsIHNlcCA9ICIiKSkgCiAgICBwcmludChwbG90KGZvcm0pKQogICAgZGV2Lm9mZigpCiAgICAKICAgIHN1bVRhYiA8LSBzdW1tYXJ5KGZvcm0pCiAgICAKICAgIAogICAgI2Zvcm0gPSBwbG0oZm9ybSwgYygic2FtcGxlX2lkIiwgImFnZSIsICJhZ2UyIikpCiAgICAKICAgICNyb3duYW1lcyhmb3JtKSA9IHBhc3RlKHJvd25hbWVzKGZvcm0pLCBvdXRjb21lLCBzZXAgPSAiICIpCiAgICByZXR1cm4oZm9ybSkKfSkKICAKc3RvcENsdXN0ZXIoY2wpCnNhdmUoaW5kRmVMb29wLCBmaWxlPXJlZ1JvYnVzdEZpbGUpCn0gZWxzZSB7CiAgbG9hZCgicmVnUm9idXN0RmlsZS5SRGF0YSIpCn0KYGBgCgoKQW5kIGNvbWJpbmUgbW9kZWwgb3V0cHV0cyBpbnRvIHRhYmxlcyBmb3IgZWFjaCBtb2RlbAoKYGBge3J9Cm1vZEV4cG9ydCA8LSBsYXBwbHkoaW5kRmVMb29wLCBmdW5jdGlvbihtb2RlbHMpewogIGRvLmNhbGwocmJpbmQsIG1vZGVscykKfSkKCmZvcihpIGluIDE6bGVuZ3RoKG1vZEV4cG9ydCkpewogIHdyaXRlLmNzdihtb2RFeHBvcnRbaV0sIGZpbGU9cGFzdGUwKCJvdXRwdXQvIiwicmVnT3V0cHV0XyIsIGksICIuY3N2IiksIHJvdy5uYW1lcyA9IFQpCn0KCmBgYAoKSW4gdGhlIGluZGl2aWR1YWwgZml4ZWQgZWZmZWN0IG1vZGVsIGFib3ZlLCB0aGUgbmFpdmUgbW9kZWwgd291bGQgb25seSBpbmNsdWRlIGEgY2xpZW50IGluZGljYXRvciBhbmQgaW5kaXZpZHVhbCBmaXhlZCBlZmZlY3RzLiBJZiB3ZSBhZGQgc2Vhc29uLCB3ZSBsb3NlIHNpZ25pZmljYW5jZSBvbiBhbG1vc3QgZXZlcnl0aGluZy4gSSdkIGd1ZXNzIHRoYXQgYXMgd2UgYWRkIG1vcmUgbGlrZWx5IGNvbnRyb2xzIHdlIGFkZGl0aW9uYWxseSBsb3NlIHNpZ25maWNhbmNlLiBJJ3ZlIGluY2x1ZGVkIGFnZSBhbmQgYWdlIHNxdWFyZWQgYWxvbmcgdGhlIGxpbmVzIG9mIFtIaWNrcyBldC5hbF0oaHR0cDovL3d3dy5uYmVyLm9yZy9wYXBlcnMvdzIzMjUzKS4KCgpgYGB7cn0KZmluYWxNb2RlbCA8LSBtb2RFeHBvcnRbNF0KCmthYmxlKGZpbmFsTW9kZWwsIGZvcm1hdD0ibWFya2Rvd24iKQp3cml0ZS5jc3YoZmluYWxNb2RlbCwgZmlsZT0ib3V0cHV0L2luZEZlLmNzdiIpCmBgYAoKU2F2ZSBkYXRhIGZvciBjbGVhbmluZwpgYGB7cn0Kc2F2ZShmaWVsZERhdCwgZmlsZT0iZmllbGREYXRfZmluYWwuUmRhdGEiKQpzYXZlKGZpZWxkU29pbERhdCwgZmlsZT0iZmllbGRTb2lsRGF0X2ZpbmFsLlJkYXRhIikKYGBgCgoKIyBBcHBlbmRpeAoKV2hhdCBoYXBwZW5zIGlmIHdlIHJlLXJ1biBvdXQgbW9kZWwgYnV0IHdpdGggMjUlIGZld2VyIG9ic2VydmF0aW9ucy4gSSBndWVzcyB3aGF0IHdlJ3JlIGNvbmNlcm5lZCB3aXRoIGhlcmUgaXMgcG93ZXIgYW5kIHRoZSBjb25maWRlbmNlIGludGVydmFscyBhcm91bmQgb3VyIGVzdGltYXRlcy4gU2V0IHRoaXMgdXAgYW5kIGNoZWNrIGl0IG91dC4KCmBgYHtyfQojIHJlbW92ZSAyNSUKc2V0LnNlZWQoMjAxNzEwMDIpCmZpZWxkU29pbERhdCA8LSBmaWVsZFNvaWxEYXQgJT4lCiAgbXV0YXRlKAogICAgcmFuZCA9IHJub3JtKG5yb3coZmllbGRTb2lsRGF0KSwgbWVhbj0wLCBzZD0xKQogICkgJT4lCiAgYXJyYW5nZShyYW5kKQoKc2JzZXQgPC0gZmllbGRTb2lsRGF0WzE6Zmxvb3IoLjc1Km5yb3coZmllbGRTb2lsRGF0KSksXQpgYGAKCgpgYGB7cn0KIyBwb3dlcgpgYGAKCmBgYHtyfQojY2kKYGBgCgpgYGB7cn0KCmluZEZlTGlzdCA8LSBsaXN0KCJhcy5mYWN0b3IoZF9jbGllbnQpIiwgCiAgICAgICAgICAgICAgICAgIGMoImFzLmZhY3RvcihkX2NsaWVudCkiLCAiYXMuZmFjdG9yKHNhbXBsZV9pZCkiKSwKICAgICAgICAgICAgICAgICAgYygiYXMuZmFjdG9yKGRfY2xpZW50KSIsICJhcy5mYWN0b3Ioc2FtcGxlX2lkKSIsICJhcy5mYWN0b3Ioc2Vhc29uKSIpLAogICAgICAgICAgICAgICAgICBjKCJhcy5mYWN0b3IoZF9jbGllbnQpIiwgImFzLmZhY3RvcihzYW1wbGVfaWQpIiwgImFzLmZhY3RvcihzZWFzb24pIiwgImFnZSIsICJhZ2UyIikpCgoKZm9yY2VVcGRhdGUgPC0gVFJVRQojIHJ1biB0aGlzIGluIHBhcmFsbGVsIHRvIHNwZWVkIHVwIHRoZSBwcm9jZXNzCiMgbG9hZCB0aGUgZGF0YSBhbmQgdmFyaWFibGVzIGFuZCBwYWNrYWdlcyBpbnRvIHRoZSBjbHVzdGVyCnJlZ0ZpbGUgPC0gInJlZ0ZpbGVfc3ViLlJEYXRhIgojZm9yY2VVcGRhdGUgPC0gZm9yY2VVcGRhdGVBbGwKaWYoIWZpbGUuZXhpc3RzKHJlZ0ZpbGUpIHx8IGZvcmNlVXBkYXRlKSB7CmxpYnJhcnkocGFyYWxsZWwpCm5vX2NvcmVzIDwtIGRldGVjdENvcmVzKCkgLSAxCgpjbCA8LSBtYWtlQ2x1c3Rlcihub19jb3JlcywgdHlwZT0iRk9SSyIpCmNsdXN0ZXJFdmFsUShjbCwgInBsbSIpCmNsdXN0ZXJFeHBvcnQoY2wsICJmaWVsZFNvaWxEYXQiKQpjbHVzdGVyRXhwb3J0KGNsLCAia2V5U29pbFZhcnMiKQpjbHVzdGVyRXhwb3J0KGNsLCAiaW5kRmVMaXN0IikKCmluZEZlTG9vcCA8LSBwYXJMYXBwbHkoY2wsIGluZEZlTGlzdCwgZnVuY3Rpb24obW9kKXsKICBsYXBwbHkoa2V5U29pbFZhcnMsIGZ1bmN0aW9uKG91dGNvbWUpewogICAgZm9ybSA9IGxtKHJlZm9ybXVsYXRlKHRlcm1sYWJlbHMgPSBtb2QsIHJlc3BvbnNlID0gb3V0Y29tZSksIGRhdGE9c2JzZXQpCiAgICAKICAgIHBkZihmaWxlPXBhc3RlKCJvdXRwdXQvIiwgcGFzdGUwKG91dGNvbWUsIHBhc3RlKG1vZCwgY29sbGFwc2UgPSAiIikpLCAiLnBkZiIsIHNlcCA9ICIiKSkgCiAgICBwcmludChwbG90KGZvcm0pKQogICAgZGV2Lm9mZigpCiAgICAKICAgIGZvcm0gPSBwbG0oZm9ybSwgYygic2FtcGxlX2lkIiwgImFnZSIsICJhZ2UyIikpCiAgICAKICAgIHJvd25hbWVzKGZvcm0pID0gcGFzdGUocm93bmFtZXMoZm9ybSksIG91dGNvbWUsIHNlcCA9ICIgIikKICAgIHJldHVybihmb3JtKQogIH0pCiAgCn0pCnN0b3BDbHVzdGVyKGNsKQpzYXZlKGluZEZlTG9vcCwgZmlsZT1yZWdGaWxlKQp9IGVsc2UgewogIGxvYWQoInJlZ0ZpbGVfc3ViLlJEYXRhIikKfQoKCm1vZEV4cG9ydCA8LSBsYXBwbHkoaW5kRmVMb29wLCBmdW5jdGlvbihtb2RlbHMpewogIGRvLmNhbGwocmJpbmQsIG1vZGVscykKfSkKCmZvcihpIGluIDE6bGVuZ3RoKG1vZEV4cG9ydCkpewogIHdyaXRlLmNzdihtb2RFeHBvcnRbaV0sIGZpbGU9cGFzdGUwKCJvdXRwdXQvIiwicmVnT3V0cHV0U3ViXyIsIGksICIuY3N2IiksIHJvdy5uYW1lcyA9IFQpCn0KCmBgYAoKCg==